Search code examples
listkotliniterator

How to modify elements of a list as I iterate through them in Kotlin ("Val cannot be reasigned")?


I am trying to make a kotlin function that given a list of numbers and another separate number, will go over the list substracting one from each element, and then add another element at the end of the list if a condition is met. This is my code:

fun listCalculator(myList:MutableList<Int>, number:Int) {

for (i in 0..number){

     val iterator = myList.listIterator()
     for (item in iterator) {

         item -= 1

         if (item == 0) {iterator.add(10)}
         println(myList.toString())

}}}

And this is the list I am passing to the function:

var testList:MutableList<Int> = mutableListOf(1,7,0,1)

The first error I run into is on line 5, when I try to subtract 1 from the value of item: 'Val cannot be reassigned'. The second problem I have is that this code adds the new element 10 right after the element that met the (item == 0) condition, but I want it at the end of the list.


Solution

  • First of all, when iterating over a collection, we don't receive some kind of a pointer to the current item. item in your example is only a copy of the current item and modifying it would not affect the list. This is one reason why item is read-only - otherwise it would be misleading as developers would think they modified the list, but in fact they would not. In order to replace the current item we have to either use ListIterator.set() or access the item using its index.

    Secondly, it would be tricky to add new items at the end while iterating over the same collection. It is much easier to just remember the number of 0 items and add 10 items after we finish iterating.

    Solution using ListIterator.set():

    fun listCalculator(myList: MutableList<Int>, number: Int) {
        for (i in 0..number) {
            var counter = 0
            val iterator = myList.listIterator()
            for (item in iterator) {
                iterator.set(item - 1)
    
                if (item == 1) {
                    counter++
                }
            }
    
            repeat(counter) { myList += 10 }
        }
    }
    

    Solution where we iterate over indices and access the current item manually:

    fun listCalculator(myList: MutableList<Int>, number: Int) {
        for (i in 0..number) {
            var counter = 0
            for (index in myList.indices) {
                val item = --myList[index]
    
                if (item == 0) {
                    counter++
                }
            }
    
            repeat(counter) { myList += 10 }
        }
    }
    

    Also note that the outer loop does not run number times, but number + 1 times. If you intended to execute it number times, then you have to use for (i in 0 until number) { ... } or just: repeat(number) { ... }