Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin and verbose array instantiation

Let say that I have path that goes through 4 vertices. When doing rapid prototyping I would define this in java as

double[][] path = {{1.0, 2.0}, {1.0,3.0}, {3.0,4.0}, {8.0,9.0}}

Using the arrayOf, and doubleArrayOf function the same code in Kotlin would be

val path = arrayOf(doubleArrayOf(1.0, 2.0), doubleArrayOf(1.0, 2.0), doubleArrayOf(1.0,3.0), doubleArrayOf(8.0,9.0))

Which feels a bit verbose. Is there a Kotlin way of solving this ?

Edit: The use-case is answering queries in a "REPL like" environment on numerical data i.e. think Matlab or SciPy.

like image 843
Tomas Karlsson Avatar asked Mar 07 '16 10:03

Tomas Karlsson


People also ask

How do you initialize a Boolean array in Kotlin?

In Kotlin, arrays can be created using the function arrayOf() or using an Array constructor. Arrays are stored in a sequence as per the memory location is concerned.

How do you declare an array of strings in Kotlin?

There are two ways to define an array in Kotlin. We can use the library function arrayOf() to create an array by passing the values of the elements to the function. Since Array is a class in Kotlin, we can also use the Array constructor to create an array.

How do I change the size of an array in Kotlin?

In Kotlin, creating an IntArray of size N is simple. Use IntArray(n) or the appropriate type, as detailed thoroughly in hotkey's answer. In this case, x will be taken from index 0, y from index 1, etc. Save this answer.


2 Answers

As far as the stdlib goest, this is as short as it gets. You could however define a helper function yourself:

fun doubles(vararg values: Pair<Double, Double>) = values
    .map { doubleArrayOf(it.first, it.second) }
    .toTypedArray()

Usage:

fun main(args: Array<String>) {
    val path = doubles(1.0 to 2.0, 1.0 to 3.0, 3.0 to 4.0, 8.0 to 9.0)
}

This is not the most efficient solution because it involves boxing and allocation of one temporary array and list, but if you're only prototyping this should be ok.

EDIT:

I also made a version where you can add arrays of arbitrary length:

inline fun doubles(block: DoubleArrayBuilder.() -> Unit) = DoubleArrayBuilder()
        .apply(block)
        .list.toTypedArray()

class DoubleArrayBuilder {
    val list = mutableListOf<DoubleArray>()

    fun add(vararg doubles: Double) = list.add(doubles)
}

Usage:

fun main(args: Array<String>) {
    val path = doubles {
        add(2.0, 3.0, 4.0)
        add(2.0, 3.0, 4.0)
        add(2.0, 3.0, 4.0)
    }
}
like image 88
Kirill Rakhman Avatar answered Nov 15 '22 07:11

Kirill Rakhman


arrayOf and doubleArrayOf and others like them, are just top level functions in stdlib. To shorten the syntax, you can easily create your own functions with scope at the top level, within a class, or even locally within a function:

By creating:

fun pathOf(vararg points: DoubleArray): Array<out DoubleArray> = points
fun pt(x: Double, y: Double) = doubleArrayOf(x,y)

This allows:

val path = pathOf(pt(1.0, 2.0), pt(1.0, 2.0), pt(1.0, 3.0), pt(8.0, 9.0))

Which now gives the nested arrays meaning for a future reader or the code. Name the function point, pt, xy, or whatever suits your use case.

This code is only slightly longer than the original, and maybe more readable/meaningful than the Java:

double[][] path = {{1.0, 2.0}, {1.0, 3.0}, {3.0, 4.0}, {8.0, 9.0}}

These functions are just as efficient as using arrayOf and doubleArrayOf and if used repeatedly the JVM will eventually inline them, but if you are nervous you can make them inline yourself.

Kotlin is intended to be extended, any time you run into an issue like this think about how you can extend an API or change a function to get the readability you desire.

like image 25
2 revs Avatar answered Nov 15 '22 08:11

2 revs