How to get columns of two dimesional array using functional style in kotlin

Viewed 550

For example I have such a simple task: count all raws and columns which have all zeros in 2D array. So for

0 0 0
0 0 0
1 0 1

answer is 2 raws and 1 column. I can make it just like that for raws: var cntRaws = a.count { it.all { el -> el == 0 } }, but how to solve it for columns in same way?

3 Answers
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")

I couldn't think of any idomatic / functional style to do this, but I came up with an idea just create a lazily evaluated swapping function that swaps the columns with rows when it wants to pull without creating a new list.

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")
}

I tried my best to optimize it and do it in same O(n*m) steps as done with the regular row counting, since Sequences are lazily evaluated.

This is a functional way of doing it that works if all rows are the same size:

fun <T>List<List<T>>.rowToColumn() = (0 until first().size).map{row -> (0 until size).map {col-> this[col][row]  }}
Related