如何在 Kotlin 中使用函数式风格获取二维数组的列

3
例如,我有这样一个简单的任务:统计所有在2D数组中所有为零的行和列的数量。
0 0 0
0 0 0
1 0 1

答案是2行1列。 对于行,我可以像这样制作:var cntRaws = a.count { it.all { el -> el == 0 } },但如何以同样的方式解决列呢?


2
我认为你无法避免使用getter。假设所有行的长度相等,你可以这样做:a.first().indices.count { col -> a.indices.all { a[it][col] == 0 } } - Tenfour04
3个回答

2
这是一种实用的方法,适用于所有行大小相同的情况:
fun <T>List<List<T>>.rowToColumn() = (0 until first().size).map{row -> (0 until size).map {col-> this[col][row]  }}

2
我想不出任何习惯用语/功能样式来完成这个任务,但我想到了一个想法:创建一个懒惰地求值的交换函数,在需要提取时将列与行互换而不创建新列表。
fun <T> List<List<T>>.swapped() = sequence {
    var index = 0
    while (index < size) {
        yield(map { it[index] })
        index++
    }
}

fun main() {
    val list = listOf(
        listOf(0, 0, 0),
        listOf(0, 0, 0),
        listOf(1, 0, 1)
    )

    val cntRows = list.count { it.all { el -> el == 0 } }
    val cntCols = list.swapped().count { it.all { el -> el == 0 } }

    println("cntRows: $cntRows")
    println("cntCols: $cntCols")
}

我尽力优化它,并在与常规行计数相同的O(n*m)步骤中完成,因为序列是惰性求值的。

好的,虽然它比常规的2 fors占用更多的空间,但是我认为交换函数在其他任务中可能会很有用。无论如何,谢谢。 - Ilya Maximencko
@IlyaMaximencko 它确切地需要 O(n*m) 步骤,交换函数不执行任何操作,除非有人收集序列(它是中间的和无状态的)。例如,count 首先拉取第一个对象,然后序列暂停,直到 it.all() 完成,然后通过恢复暂停来拉取第二个对象。在此过程中没有形成额外的有状态列表,并将项目收集到其中。 - Animesh Sahu

2
val x = Array<IntArray>(3) { IntArray(3) { 0 } }

x[2][0] = 1
x[2][2] = 1
val raws = x.count { it.sum() == 0 }
val columns = (x.indices)
    .map { columnIndex -> x.map { it[columnIndex] } }
    .count { it.sum() == 0 }

println("total raws:$raws")
println("total col:$columns")

count { it.sum() == 0 } 将更高效地删除一个 O(n) 步骤(因为它不是序列)。 - Animesh Sahu
如果将 x.indices 更改为您自己的 indices,它就可以工作:x.first().indices。 - Ilya Maximencko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接