I'm trying to wrap my head around map and reduce operations in Kotlin. At least, I guess it's reduce what I'm trying to do.
Let's say that I have a class called Car that takes any number (varargs constructor) of CarPart. Then, I have a list of CarPart which I'll do a map operation and from the result of the operation I need to build one Car using each subelement, something along these lines:
class CarPart(val description: String)
class Car(vararg val carPart: CarPart)
val carParts = listOf(CarPart("Engine"), CarPart("Steering Wheel")))
carParts.map { it.description.toUpperCase() }
.map { CarPart(it) }
.reduce { acc, carPart -> Car(carPart) } <--- I'm struggling here, is reduce what I should be doing
to construct one car from all the subelement?
PS.1: I know that the class design could be better and not take a varargs, this is just an example of a legacy application I'm refactoring and originally that's a Java class taking varargs which I can't change now.
PS.2: The example of mapping to a String and then creating an object out of that String is just for the sake of the example. The actual code grabs an object within the list.
CodePudding user response:
You can simply use a the spread operator (*) over an array:
val mappedCarParts = carParts
.map { it.description.toUpperCase() }
.map { CarPart(it) }
.toTypedArray()
val car = Car(*mappedCarParts)
// Or even:
val car = carParts
.map { it.description.toUpperCase() }
.map { CarPart(it) }
.toTypedArray()
.let{ Car(*it) }
CodePudding user response:
You could just extract the constructor of the Car outside of the creation of the list. I don't see any reason as to why you'd want it inside.
val car = Car(
*carParts
.map { CarPart(it.description.uppercase(Locale.getDefault())) } //keep the .toUpperCase() if you are using an old version of Kotlin
.toTypedArray()
)
We need the spread operator there in order for the vararg to know that we are passing it the elements of the list and not the list itself.
