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

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)

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.

1 Like

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.


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

You can use map

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

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

use mapIndexed instead :wink:

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.


Not sure if it’s a douche move to revive this topic – if so, then I apologize – but in the interest of helping anyone still looking for a solution to this issue, I’ll give it a go:

My take on this was a function that took a new value and a lambda, and returned a new list where the elements for which the lambda returned true were replaced:

fun <T> List<T>.replace(newValue: T, block: (T) -> Boolean): List<T> {
  return map {
    if (block(it)) newValue else it

On replacing 1 with 99 in the sample:

val list = listOf(1, 2, 3)
val updatedList = list.replace(newValue = 99) { it == 1 }

This would of course replace every insteance of 1, but could also be complemented with a similar replaceFirst or replaceLast function as well.

Hope this helps anyone looking for a similar solution!


Very elegant piece of code… thanks👍🏼

1 Like

What would be even faster is to do this:

fun <T> List<T>.update(index: Int, item: T): List<T> = toMutableList().apply { this[index] = item) } 

since it’ll just do one array copy under the hood and then it’ll replace that one element in the array.

1 Like