Omar Khaled
Omar Khaled

Reputation: 499

pure function to change element in list

I want function return new list with the new value without mutate the original list

fun <T> change(list:List<T>,index:Int,value:T){
  

}

examble in typescript

function change<T>(array:T[],index:number,value:T){
   return [...array.slice(0,index),value,...array.slice(index + 1)]
}

Upvotes: 1

Views: 199

Answers (3)

gpunto
gpunto

Reputation: 2842

If you don't want to use persistent collections as @broot is suggesting, you can just use mapIndexed which is O(n):

fun <T> List<T>.change(index: Int, value: T): List<T> =
    mapIndexed { i, originalValue -> if (index == i) value else originalValue }

Upvotes: 2

broot
broot

Reputation: 28402

Adding to @Sweeper answer, you can also consider using persistent collections. If you need to perform such operations frequently, persistent collections could be much more performant approach both CPU- and memory-wise, by avoiding the data copying. In simple words, they create a new collection by keeping a reference to the original one and "remembering" the modification to apply it on the fly.

There is at least one implementation of persistent collections for Kotlin, provided by the Kotlin team themselves: https://github.com/Kotlin/kotlinx.collections.immutable . You can use it like this:

val list1 = persistentListOf(1, 2, 3, 4, 5)
val list2 = list1.set(2, 8)

println(list1) // [1, 2, 3, 4, 5]
println(list2) // [1, 2, 8, 4, 5]

Upvotes: 0

Sweeper
Sweeper

Reputation: 272725

A similar approach to your Type Script code would be:

fun <T> List<T>.with(element: T, atIndex: Int) =
    subList(0, atIndex) + element + subList(atIndex + 1, size)

or

fun <T> List<T>.with(element: T, atIndex: Int) =
    take(atIndex) + element + drop(atIndex + 1)

Usage:

val list = listOf(1,2,3,4,5)
println(list.with(10, atIndex = 2))

Note that this creates many temporary lists, which may be undesirable (I don't know if the TypeScript code also does that). If you don't want that, you can just create a mutable list, and add things to it (subList returns only a view of the list, and doesn't create anything new):

fun <T> List<T>.with(element: T, atIndex: Int) =
    ArrayList<T>(size).apply {
        addAll([email protected](0, atIndex))
        add(element)
        addAll([email protected](atIndex + 1, [email protected]))
    }

Or you can use the experimental API buildList

@OptIn(ExperimentalStdlibApi::class)
fun <T> List<T>.with(element: T, atIndex: Int) =
    buildList(size) {
        addAll([email protected](0, atIndex))
        add(element)
        addAll([email protected](atIndex + 1, [email protected]))
    }

Upvotes: 3

Related Questions