Reputation: 587
Quite often I am navigating a two-dimensional image matrix of pixels or a three-dimensional volumetric data set. Typically the underlying data structure is a one-dimensional array of some primitive type like Double
or Int
. The multi-dimensional nature is navigated through by nested for-loops as illustrated below.
Given that Kotlin does not currently support the typically C and Java-like for-loop structure, there seems some lost flexibility. I'm wondering if there is a clever iterator or Kotlin syntax to make this more elegant.
In Java below, we have the ability to capture the whole iteration concisely by embedding the master index i
into the for-loops and only involving implicit increment operations which are presumably computationally efficient (compared to division and modulo)...
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;
}
}
}
In Kotlin as follows, I find a solution where the index i
is forced to have scope outside the loop block. Also the i++
line is somewhat buried and separated from the loop structure. I'm missing in this situation the elegant Kotlin syntax such as 'builders', no semi-colons, etc. I humbly submit that this is because the for-loop flow-control structure is less expressive in Kotlin. Admittedly, this is not critical, but more of a disappointment.
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++
}
}
}
Upvotes: 2
Views: 6124
Reputation: 587
Here is the answer I mentioned involving division and modulo
fun main(args : Array<String>) {
val nrow = 1000
val ncol = 1000
val size = nrow * ncol
val data=DoubleArray(size,{(it/ncol * it%ncol).toDouble()})
}
Upvotes: 0
Reputation: 7001
You can calculate the index based on the offsets...
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()
}
}
}
You can wrap the array, simplifying access...
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()
}
}
}
Upvotes: 4
Reputation: 1275
This is one way of creating your array in Kotlin, without using i
(or for
loops):
val data = (0 until nrow).flatMap { r ->
(0 until ncol).map { c ->
(r * c).toDouble()
}
}.toDoubleArray()
Upvotes: 2