1

I have this code that keeps giving me a "Val cannot be reassigned" error but I can't seem to change the variable to a var instead of val. I simply want to be able to set a string value to my cell reference so I can access the values later like this myStringsArrayList.add(deviceData.cellOne).

Here is my code:

val cells = listOf(
            deviceData.cellOne,
            deviceData.cellTwo,
            deviceData.cellThree,
            deviceData.cellFour,
            deviceData.cellFive,
            deviceData.cellSix,
            deviceData.cellSeven,
            deviceData.cellEight,
            deviceData.cellNine,
            deviceData.cellTen,
            deviceData.cellEleven,
            deviceData.cellTwelve,
            deviceData.cellThirteen,
            deviceData.cellFourteen
        )

        for ((i, cell) in cells.withIndex()) {
            val value = data[2 + i].toDouble() / 100 + 3.52
            val cellNumberString = (i + 1).toString()
            val formattedString = "Cell $cellNumberString: %.2fV".format(value)
            cell = formattedString // THIS IS WHERE THE PROBLEM IS (cell is a val)
        }

Does anyone know how I can get around this and achieve the functionality that I want?

I tried using a listIterator() but it hasn't seemed to work the way that I want it to.

Here is my attempt with the listIterator():

val cells = mutableListOf(
            deviceData.cellOne,
            deviceData.cellTwo,
            deviceData.cellThree,
            deviceData.cellFour,
            deviceData.cellFive,
            deviceData.cellSix,
            deviceData.cellSeven,
            deviceData.cellEight,
            deviceData.cellNine,
            deviceData.cellTen,
            deviceData.cellEleven,
            deviceData.cellTwelve,
            deviceData.cellThirteen,
            deviceData.cellFourteen)

        val iterate = cells.listIterator()
        while (iterate.hasNext()) {
            var cell = iterate.next()
            val value = data[2 + iterate.nextIndex()].toDouble() / 100 + 3.52
            val cellNumberString = (iterate.nextIndex() + 1).toString()
            val formattedString = "Cell $cellNumberString: %.2fV".format(value)
            cell = formattedString
        }
Dylon Jaynes
  • 166
  • 11
  • 1
    Try `val cells = listOf().map { }`, where your conversion logic goes in the `map` lambda. – CommonsWare Apr 11 '22 at 20:55
  • Take a look at [this](https://stackoverflow.com/a/34608552/4778990) answer. It may be helpful. – Michel Fortes Apr 11 '22 at 20:57
  • @MichelFortes I read through that post and tried using a `listIterator()` but it's not really working. I will make an edit on my question so you can see. Maybe I'm not using it correctly? I need it to change the variable in my custom DeviceData object but it seems like I can't do that. – Dylon Jaynes Apr 11 '22 at 21:40

2 Answers2

3

You can't make that a var, and there's no reason to anyway!

for ((i, cell) in cells.withIndex()) {
    ...
    cell = formattedString // THIS IS WHERE THE PROBLEM IS (cell is a val)
}

You're creating a for loop there on a collection, with an index, and giving it a block of code to run for each loop. So when the loop runs, you're provided with two parameters - the current item from the collection, and its index in that collection.

These are just internal variables for use in the loop - you can't reassign them, because they're the values being passed in. Even if you could, you'd just be changing the values of those local variables.

What you're probably trying to do is update the cells list, taking the current item in the loop, finding it in cells, and replacing it. You'd have to actually update cells to do that! Change the list itself. You could do that with cells[i] = formattedString - but because you're currently iterating over that cells collection, you shouldn't modify it!

You could copy the source list, but the typical Kotlin way is to create a new list, using map (which transforms values):

cells.mapIndexed { i, cell ->
    val value = data[2 + i].toDouble() / 100 + 3.52
    val cellNumberString = (i + 1).toString()
    // last expression is the return value, i.e. the formatted string
    "Cell $cellNumberString: %.2fV".format(value)
}

That will spit out a new (immutable) list where each cell has been mapped to that formatted string version.

You could make cells a var and just reassign it:

cells = cells.mapIndexed { ... }

or just chain the map call when you initialise the val, so that end result is what gets assigned:

val cells = listOf(
    ...
).mapIndexed { ... }

But you're not actually using cell in that loop anyway, just using the index to generate values. You can create a list like this:

val data = List(14) { i ->
    val value = data[2 + i].toDouble() / 100 + 3.52
    // you can calculate the index inside the string by using braces
    "Cell ${i + 1}: %.2fV".format(value)
}

It all depends whether you need to keep that list of devicedata values around for anything (if so use it to create another list)

cactustictacs
  • 17,935
  • 2
  • 14
  • 25
  • Wow, I like this solution quite a bit! I ended up using the chained map call as you suggested, and it worked great! – Dylon Jaynes Apr 12 '22 at 14:44
1

You may wanna use Interator this way:

val list = mutableListOf("One", "Two", "Three", "Four")
println(list.joinToString(" "))

val iterator = list.listIterator()
while(iterator.hasNext()) {
    val value = iterator.next()
    if (value == "Two") {
        iterator.set("xxxxxx")
    }
}
println(list.joinToString(" "))

Use the 'set' method.

Michel Fortes
  • 819
  • 8
  • 12