在 Kotlin 中使用嵌套的 for 循环导航多维数组



我经常浏览像素的二维图像矩阵或三维体积数据集。 通常,底层数据结构是某种基元类型的一维数组,如DoubleInt。 多维性质通过嵌套的 for 循环进行导航,如下图所示。

鉴于 Kotlin 目前不支持典型的 C 和类似 Java 的 for 循环结构,似乎失去了一些灵活性。 我想知道是否有一个聪明的迭代器或 Kotlin 语法来使其更优雅。

在下面的 Java 中,我们能够通过将主索引i嵌入到 for 循环中并仅涉及隐式增量操作来简洁地捕获整个迭代,这些操作可能在计算上是高效的(与除法和模相比)......

public static void main(String[] args) {
int nrow=1000, ncol=1000;
int size=nrow*ncol;
double[] data = new double[size];
for (int i=0, r = 0; r < nrow; r++) {
for (int c = 0; c < ncol; c++,i++) {
data[i]= r*c;
}
}
}

在 Kotlin 中,我找到了一个解决方案,其中索引i被迫在循环块之外具有范围。 此外,i++线在某种程度上被埋入并与环形结构分离。 在这种情况下,我缺少优雅的 Kotlin 语法,例如"构建器"、没有分号等。我谦虚地认为,这是因为 for 循环流控制结构在 Kotlin 中表现力较差。 诚然,这并不重要,但更令人失望。

fun main(args : Array<String>) {
val nrow = 1000
val ncol = 1000
val size = nrow * ncol
val data = DoubleArray(size)
var i = 0
for(r in 0 until nrow) {
for(c in 0 until ncol) {
data[i] = (r * c).toDouble()
i++
}
}
}

简单的方法

您可以根据偏移量计算指数...

fun main(args : Array<String>) {
val nrow = 1000
val ncol = 1000
val size = nrow * ncol
val data = DoubleArray(size)
for(r in 0 until nrow) {
for(c in 0 until ncol) {
data[(ncol*r) + c] = (r * c).toDouble()
}
}
}

包装方式

您可以包装阵列,从而简化访问...

class ArrayWrapper<T>(val height: Int, val width: Int, val default: Int) {
private val data: Array<Any?> = Array(height, {default})
operator fun get(x: Int, y: Int) = data[(width * y) + x] as T
operator fun set(x: Int, y: Int, value: T) {
data[(width * y) + x] = value
}
val rowIndices = (0 until width)
val columnIndices = (0 until height)
}
fun main(args : Array<String>) {
val nrow = 1000
val ncol = 1000
val data = ArrayWrapper<Double>(nrow, ncol, 0)
for(r in data.rowIndices) {
for(c in data.columnIndices) {
data[r, c] = (r * c).toDouble()
}
}
}

这是在 Kotlin 中创建数组的一种方法,无需使用i(或for循环):

val data = (0 until nrow).flatMap { r ->
(0 until ncol).map { c ->
(r * c).toDouble()
}
}.toDoubleArray()

这是我提到的涉及除法和模的答案

fun main(args : Array<String>) {
val nrow = 1000
val ncol = 1000
val size = nrow * ncol
val data=DoubleArray(size,{(it/ncol * it%ncol).toDouble()})
}

最新更新