Concatenating arrays in Koltin

2 minute read

Adding the contents of one array to another would seem a very simple task. It Kotlin it’s a little bit more complicated…
In my case I wanted to add one additional element to the end of an array. This is what I found.
First up: The array size is immutable. This is the same as Java or C++ as memory is only allocated for the size the array is, so adding more requires a new array to be created(allocated), and the contents of the two arrays copied in. So lets try this with IntArray:

//Copy using arraycopy
fun catTwoIntArrays1(array1 :IntArray, array2 :IntArray) : IntArray {
    val newArray = IntArray(array1.size + array2.size)
    System.arraycopy(array1, 0, newArray, 0 , array1.size)
    System.arraycopy(array2, 0, newArray, array1.size , array2.size)
    return newArray
}

Here we are creating a new array with and using the Java function to copy the original arrays into the new array.


Next we use for loops to do the copying:

//Copy using for loops
fun catTwoIntArrays2(array1 :IntArray, array2 :IntArray) : IntArray {
    val newArray = IntArray(array1.size + array2.size )

    for ((index, value) in array1.withIndex()) {
        newArray[index] = value
    }

    for ((index, value) in array2.withIndex()) {
        newArray[index + array1.size] = value
    }
    return newArray
}

Next we are going to use the Array constructor to do the element copying

//Copy using the lamda in the constructor
fun catTwoIntArrays3(array1 :IntArray, array2 :IntArray) : IntArray {
    return IntArray(array1.size + array2.size,
            { if (it<array1.size) array1[it] else array2[it-array1.size]})
}

The lambda passed as the second parameter to the constructor fills the new array. The previous two examples could not use the Array<> because the constructor requires a lambda to construct the contents. But with this version I can now use Array<>

//Copy using the lamda in the constructor
inline fun <reified T> catTwoArrays3(array1 :Array<T>, array2 :Array<T>) : Array<T> {
    return Array<T>(array1.size + array2.size,
            { if (it<array1.size) array1[it] else array2[it-array1.size]})
}

All of this will have complexity of O(n+m) and a size of O(n+m) because we are creating a new array, and coping element from both into the new array.


My next though is could I be a bit lazy about this. Could I do this through a delegate? The delegate would need to handle the get operator overloading, so it seemed this was the wrong approach, but I simple class could do it.

//Create a class that mimics an immutable Array<>
class CatTwoArrays<T>(internal val array1 : Array<T>, internal val array2 : Array<T>) {
    public operator fun get(index: Int): T {
        return if (index < array1.size) array1[index] else array2[index - array1.size]
    }

    public val size: Int = array1.size + array2.size

    internal inner class CatTwoArraysIterator() : Iterator<T> {
        internal var position = 0

        override fun hasNext(): Boolean = (position >= 0) && (position < array1.size + array2.size)

        override fun next() = CatTwoArrays@get(position++)
    }

    public operator fun iterator(): Iterator<T> = CatTwoArraysIterator()
}

Here I am saving the two arrays into internal var’s. I then overload the size and get operator. I also provide a Iterator. Size will not increase and construction complexity will be O(1)


Takeaways Array<T> and IntArray/ByteArray/ShortArray/CharArray/BooleanArray/etc… all have simular interfaces, but share no inheritance and are also final. So my custom Array requires it’s own extension functions to be defined. I should be looking at ArrayList<> which is more powerful, yet still has the continuous buffer which is super efficient with modern processors.

Links Gist Full Source Research / Alternatives

Original post

Updated: