Jakub Mosakowski
Jakub Mosakowski

Reputation: 549

Mapping arrays to list of objects kotlin

I'm wondering about methods of mapping multiple arrays into one list of object.

I mean e.g. I have

val a = arrayOf("A1","A2","A3")
val b = arrayOf("B1","B2","B3")

and

data class SomeClass(val v1:String, val v2:String)

I want to parse it in elegant way to have list like that:

val list = listOf(SomeClass("A1","B1"),SomeClass("A2","B2"),SomeClass("A3","B3"))

I assume they are of the same length. The only way I thought of is:

val list = mutableListOf<SomeClass>() 
for (i in a.indices) 
            array.add(SomeClass(a[i],b[i])

Is there a better, more elegant solution (maybe using Collecions.zip or Array.map)?

Upvotes: 8

Views: 10146

Answers (3)

Sergei Buvaka
Sergei Buvaka

Reputation: 611

You can write some custom fun like this:

inline fun <T, R, E, V> Iterable<T>.zipThree(other1: Iterable<R>, other2: Iterable<E>, transform: (T, R, E) -> V): List<V> {
        val first = iterator()
        val second = other1.iterator()
        val third = other2.iterator()
        val list = ArrayList<V>()
        while (first.hasNext() && second.hasNext()) {
            list.add(transform(first.next(), second.next(), third.next()))
        }
        return list
    }

And use this transform for getting List

val strings = listOf("1", "2")
        val ints = listOf(1, 2)
        val boolean = listOf(true, false)

        val listYoutObjects = strings.zipThree(ints, boolean) { one, two, three -> YouObject(one, two, three) }

Upvotes: 0

Roland
Roland

Reputation: 23242

Try Array.zip and then map:

val list = a.zip(b)
            .map { SomeClass(it.first, it.second) }

or if you like it more:

val list = a.zip(b)
            .map { (a, b) -> SomeClass(a, b) }

Note that if both arrays differ in size, the additional values are ignored. Note also that this will create intermediate Pairs (which is the default transformation function of zip). Even though I like the explicit map more, @hotkeys solution regarding the overloaded method is more appropriate (you spare that hidden Pair-transformation):

val list = a.zip(b) { a, b -> SomeClass(a, b) }

And where the overloaded method probably shines, is when using references instead:

a.zip(b, ::SomeClass)

Which will work as long as you have a constructor matching the zipped arguments and doesn't work out of the box for the Pair (yet?).

Upvotes: 9

hotkey
hotkey

Reputation: 147911

Improving on @Roland's answer, you can use the zip overload that accepts a two-argument function for mapping the pairs immediately:

val result = a.zip(b) { x, y -> SomeClass(x, y) }

Upvotes: 4

Related Questions