I have a list of objects of type MyObject
:
data class MyObject(val name: String?, val age: Int)
I want to go through the list, and for those values with name == null
, I'd like to copy the value on the previous item, if present. And if possible id like to carry the changes over, so if item 0 has name, 1 doesnt, and 2 doesnt; 1 should get name from 0, and 2 should get name from 1 which got its name from 0.
I hope this makes sense.
I sense this is something there might be a builtin function for like reduce, scan or something similar but I cant seem to get to the solution?
Example input:
[ MyObject("Paul", 21),
MyObject(null, 23),
MyObject(null, 17),
MyObject("Mike", 45),
MyObject("Laura", 20),
MyObject(null, 60)
]
Example output:
[ MyObject("Paul", 21),
MyObject("Paul", 23),
MyObject("Paul", 17),
MyObject("Mike", 45),
MyObject("Laura", 20),
MyObject("Laura", 60)
]
While there is a built-in scan
(aka runningFold
), it is more appropriate to use runningReduce
(as suggested by lukas.j) here, since you do not need to use a dummy object as the initial value.
val result = list.runningReduce() { acc, obj ->
MyObject(obj.name ?: acc.name, obj.age)
}
This creates a new list with new MyObject
instances.
You can also fold
with a mutable list:
val result = list.fold(mutableListOf<MyObject>()) { list, obj ->
list.apply {
val name = obj.name ?: lastOrNull()?.name
add(MyObject(name, obj.age))
}
}
The idea is to use the name of the object last added to the list, if obj.name
is null.
Alternatively, if you want to mutate the MyObject
s in place, you should make name
a var
:
data class MyObject(var name: String?, val age: Int)
and use zipWithNext
:
list.zipWithNext { prev, curr ->
if (curr.name == null) {
curr.name = prev.name
}
// shorter but less readable IMO:
//curr.name = curr.name ?: prev.name
}