Best way to "replace" an element of an immutable list


#1

What is the best way to “replace” an element of an immutable list?

I came up with the following ugly solution:

val list = listOf(1, 2, 3)
val updatedList = listOf(99, *(list.subList(1, list.size).toTypedArray()))

However, despite being a bit noisy it would get even worse if you want to replace an element in the middle of the list. If I’m not overlooking something, I think Kotlin needs some more methods like the updated and patch methods of Scala’s List type.

My example would look like this in Scala:

val list = List(1, 2, 3)
val updatedList = list.updated(0, 99)

#2

Well firstly you could think about using a mutable list. Also listOf does give you a mutable implementation hidden behind a readonly interface, so you could cast it (in most situations).
Otherwise I would use mapIndexed and update the list that way.

Maybe it does. I don’t know.


#3

I don’t think it is good idea to cast immutable list to mutable since it breaks the contract and is not guaranteed to work. The correct way is to either use mutableListOf from the beginning or create mutable copy via toMutableList extension.


#4

Now, there’s an issue suggesting to implement these methods for Kotlin Lists.


#5

You can use map

fun <E> Iterable<E>.replace(old: E, new: E) = map { if (it == old) new else it }

#6

That would only work if all elements are distinct. I need something to perform a positional replacement.


#7

use mapIndexed instead :wink:


#8

No one posted how to actually do this so I thought I would.

fun <E> Iterable<E>.updated(index: Int, elem: E) = mapIndexed { i, existing ->  if (i == index) elem else existing }

If I am understanding patched right, it is a bit harder but should be doable

fun <E> Iterable<E>.patched(from: Int, that: Iterable<E>, replaced: Int): Iterable<E> {
    return take(from) + that + drop(from + replaced)
}

I didn’t really bother to try to optimize anything, just get it to work.