RandomCoder
RandomCoder

Reputation: 161

Why kotlin map.indexed returns List<Any> insteand of List<MyObject>

i'm playing a little bit with Kotlin and i don't understand this so, maybe someone can explain it to me.

I have a data class which is:

data class Person (var name : String, var age : Int)

And i want to create a List which contains the Person with the multiplied age multiplied per 2, only on even items. So i created a new List and create a mutableList from it because i want to change their age. I did it in the following way:

    val personA = Person("john", 25)
    val personB = Person("Ane", 10)
    val personC = Person("will", 20)
    val personList = listOf(personA, personB, personC)
    var mutablePersons = mutableListOf<Person>()
    mutablePersons.addAll(personList)

And now i'm trying to create a new list with the items from mutablePersons modified. So i already did the following:

val mutablePersonsAgeChanged = mutablePersons.mapIndexed { index, person ->
        if (index.rem(2) == 0) {
            person.age = person.age * 2
        }
    }

And.. there is something i'm not doing well, because mutablePersonAgeChanged is List<Any> and i want a List<Person>.

So, my question is. What im doing wrong? How can make this mapIndexed Returns List<Person>

Upvotes: 9

Views: 25467

Answers (2)

Mikezx6r
Mikezx6r

Reputation: 16905

The mapIndexed will pass each item, and its index into the Lambda. It then adds the result of the Lambda to the new list. In your case, the return value of the Lambda is the if (as most items are expressions in Kotlin).

The result of the if is either Unit in the case of index % 2 == 0 because the setter for age returns a Unit.

If the if is false, it will also return Unit.

To fix it, you need to return person at the end of the map.

So if you made your code as below, it will work.

val mutablePersonsAgeChanged = mutablePersons.mapIndexed { index, person ->
    if (index.rem(2) == 0) {
        person.age = person.age * 2
    }
    person
}

It's also not necessary to create a List, and then add all the elements to a mutableList. Just change listOf(personA, personB, personC) to mutableListOf(personA, personB, personC)

Upvotes: 4

Omar Mainegra
Omar Mainegra

Reputation: 4184

In your case the function passed as the parameter of mapIndexed was inferred to Any because you miss the else branch of your if statement. Also, I'd like to mention that mapIndexed is like map but with the index of the element, so you need to pass a function that transforms every element.

Example

data class Person (val name : String, val age : Int)

val personList = listOf(
    Person("John", 25), 
    Person("Ane", 10), 
    Person("will", 20)
)

val personListAgeChanged = personList.mapIndexed { index, person ->
    if (index.rem(2) == 0) person.copy(age = person.age*2)
    else person
}

println(personListAgeChanged)

Output

[Person(name=john, age=50), Person(name=Ane, age=10), Person(name=will, age=40)]

In this case, you pass a function that doubles the age of each person in the list, please notice that never any variable or list is mutated, which should be the prefered approach.

Upvotes: 17

Related Questions