Kotlin 科特林联合公司';N';通过对每个元素求和将其列在一起

Kotlin 科特林联合公司';N';通过对每个元素求和将其列在一起,kotlin,collections,Kotlin,Collections,我试图将N个列表合并在一起,将每个元素相加,并输出一个最终列表和结果。下面是一个可视化: List 1: { 1, 2, 3 } List 2: { 4, 5, 6 } List 3: { 7, 8, 9 } ... List N: { X, X, X } 如果我们将前三者结合起来,结果将是: List Result: { 12, 15, 18 } 我想继续对每个索引处的元素求和,简洁、内联、性能最佳。 我知道zip操作符在这里会有所帮助(很容易做到list1.zip(list2)并添加pa

我试图将N个列表合并在一起,将每个元素相加,并输出一个最终列表和结果。下面是一个可视化:

List 1: { 1, 2, 3 }
List 2: { 4, 5, 6 }
List 3: { 7, 8, 9 }
...
List N: { X, X, X }
如果我们将前三者结合起来,结果将是:

List Result: { 12, 15, 18 }
我想继续对每个索引处的元素求和,简洁、内联、性能最佳。

我知道zip操作符在这里会有所帮助(很容易做到list1.zip(list2)并添加pair.first和pair.second),但它不会处理多个列表

我自学了Kotlin收集操作,试图找到一个解决方案——我研究了使用fold、reduce、flatMap、zip、groupBy,并可能将列表转换为序列以利用每个元素方面。但我似乎找不到一个干净的方法将这些操作链接在一起以获得令人满意的结果

其他信息:

我现在有一个名为padStart(为简洁起见隐藏)的扩展方法来帮助确保所有嵌套列表的长度相同,然后我笨拙地创建了一个临时列表,在迭代时向其中添加值:

myNestedLists
    .run {
        // Calculate largest list size of 'n' lists
        val largestSize = map { it.size }.max() ?: 0 
        // Pad lists with zeroes if size < largestSize
        map { it.padStart(largestSize, 0.0) }
    }
    .run {
        // Create temporary list, add all of the first elements to it
        val combinedList: MutableList<Double> = mutableListOf()

        combinedList.addAll(this.first())

        // Now, for each nested list, add each individual element with the combined value at combinedList[index]
        drop(1).forEach {
            it.forEachIndexed { index, value ->
                combinedList[index] += value
            }
        }

        // Return the final result
        combinedList
    }
MynestedList
.跑{
//计算“n”个列表的最大列表大小
val largestSize=map{it.size}.max()?:0
//如果大小<最大大小,则用零填充列表
映射{it.padStart(最大大小,0.0)}
}
.跑{
//创建临时列表,将所有第一个元素添加到其中
val combinedList:MutableList=mutableListOf()
combinedList.addAll(this.first())
//现在,对于每个嵌套列表,在combinedList[index]处添加每个单独的元素和组合值
下降(1)forEach{
it.foreachinedexed{index,value->
组合列表[索引]+=值
}
}
//返回最终结果
组合列表
}

这个解决方案是可行的,但它很难阅读,也不是很干净。我在找一个更好的

我会做如下的事情

fun getResult(nestedList: List<List<Int>>) : List<Int> {
    val list = mutableListOf<Int>()
    val maxSize = nestedList.maxBy{it.size}?.size ?: 0

    repeat(maxSize) { i ->
        val sum = nestedList.sumBy{if(i<it.size) it[i] else 0}
        list.add(sum)
    }
    return list
}
fun getResult(nestedList:List):List{
val list=mutableListOf()
val maxSize=nestedList.maxBy{it.size}?.size?:0
重复(最大大小){i->
val sum=nestedList.sumBy{if(i”。然后我笨拙地创建了一个临时列表..”
这并不笨拙

在这种情况下,“保持简单,愚蠢”

fun-sumLists(vararg-lists:List,sum:(a:T,b:T)->T):List{
val result=ArrayList(lists.first())
lists.drop(1).forEach{l->
l、 前加工指数{i,v->
结果[i]=和(结果[i],v)
}
}
返回result.toList()
}
趣味主线(args:Array){
val l1=列表(1、2、3)
val l2=列表(4、5、6)
val l3=列表(7,8,9)
打印(sumLists(l1、l2、l3,sum=Int::plus))
}

功能性和直截了当:

lists.maxBy { it.size }!!.indices
     .map { index ->
        lists.mapNotNull { it.getOrNull(index) }.sum()
     }
如果您关心性能,编译器无论如何都会对其进行优化

编辑:


如果列表的数量非常大或者值是由服务获取的,您可以在
map
操作中使用协程。

正如您所观察到的
zip
对两个列表都能很好地完成这项工作。如果我们使用
fold
,那么我们可以使用
zip
将每个列表与累加器值组合起来,并永远重复这个过程嵌套列表中的y列表

如果我们可以假设所有列表都是三个元素(根据最初的问题),我们可以这样做:(免责声明:最低限度测试,使用风险自负:)


就性能而言,您最好使用可变列表和简单的旧循环来增加每个值,但我认为
折叠
邮政编码
满足清洁度要求。

发布的每个解决方案似乎都有效,但这一个(结合我自己的填充方法)根据问题,最终成为最快、最简洁的。谢谢!
lists.maxBy { it.size }!!.indices
     .map { index ->
        lists.mapNotNull { it.getOrNull(index) }.sum()
     }
fun sumList(xs: List<List<Int>>): List<Int> =
        xs.fold(listOf(0, 0, 0)) { x, y ->
            x.zip(y, Int::plus)
        }
fun List<Int>.padTo(requiredSize: Int) =
        if (size < requiredSize) {
            plus(generateSequence { 0 }.take(requiredSize - size))
        } else {
            this
        }

fun sumVariableLists(xs: List<List<Int>>): List<Int> =
        xs.fold(emptyList()) { x, y ->
            val maxSize = maxOf(x.size, y.size)
            x.padTo(maxSize).zip(y.padTo(maxSize), Int::plus)
        }

@Test
fun example() {
    val x = listOf(
            listOf(1, 2, 3, 10),
            listOf(4, 5, 6),
            listOf(7, 8, 9, 11))

    assertEquals(listOf(12, 15, 18, 21), sumVariableLists(x))
}