listkotlincollectionsslice

Difference between List.subList and slice in Kotlin


I recently realised there are two very similar functions in Kotlin for getting a portion of a List, but I'm unsure of the difference:

The documentation for List.subList says:

Returns a view of the portion of this list between the specified fromIndex (inclusive) and toIndex (exclusive). The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.

Structural changes in the base list make the behavior of the view undefined.

whereas the documentation for slice says:

Returns a list containing elements at indices in the specified indices range.

Or

Returns a list containing elements at specified indices.

It seems that the key differences are that the first one returns a "view of the portion" of the list, and whether non-structural changes are reflected? However I'm not quite sure what this means.

I looked at the source code for the slice function:

public fun <T> List<T>.slice(indices: IntRange): List<T> {
    if (indices.isEmpty()) return listOf()
    return this.subList(indices.start, indices.endInclusive + 1).toList()
}

But it returns a list from the subList function.

Could someone explain the differences between these two functions and when you might want to use one over the other?


Solution

  • The key in List<T>.slice function is the .toList() at the end, which will create a new List with the elements, using a shallow element copy.

    For summary:

    You can see differences here: https://pl.kotl.in/-JU8BDNZN

    fun main() {
        val myList = mutableListOf(1, 2, 3, 4)
        val subList = myList.subList(1, 3)
        val sliceList = myList.slice(1..2)
        println(subList) // [2, 3]
        println(sliceList) // [2, 3]
        
        myList[1] = 5
        println(subList) // [5, 3]
        println(sliceList) // [2, 3]
    }