Erez Ben Harush
Erez Ben Harush

Reputation: 867

Zip 2 kotlin lists by a class property

Given the following person definitions:

open class Person(val name: String, val age: Int)
object EmptyPerson:Person("", 0)

And the following data:

val left = listOf(Person("Tinky-winkey", 1), Person("lala", 2))
val right = listOf(Person("Dipsy", 3), Person("Tinky-winkey", 4))

Is it possible to zip theleft and right lists based on the name property to yields:

val result = listOf(
        Pair(Person("Tinky-winkey", 1), Person("Tinky-winkey", 4)),
        Pair(Person("lala", 2), EmptyPerson),
        Pair(EmptyPerson, Person("Dipsy", 3))
    )

In a way that keeps the left elements on the left side of the pair().

Something like left.zipByProperty {right, p->p.name}

Maybe zip is not the right way to go?

Upvotes: 0

Views: 1127

Answers (1)

Tenfour04
Tenfour04

Reputation: 93759

zip doesn't handle matching items by anything besides their position in the collection.

I think this would do what you're describing. It's best to create Maps first to keep the complexity down, unless these are always extremely short lists.

inline fun <T, K> zipBy(first: List<T>, second: List<T>, default: T, keySelector: (T)->K): List<Pair<T, T>> {
    val firstByKey = first.associateBy(keySelector)
    val secondByKey = second.associateBy(keySelector)
    return (firstByKey.keys + secondByKey.keys)
        .map { (firstByKey[it] ?: default) to (secondByKey[it] ?: default) }
}

Usage:

val result = zipBy(left, right, EmptyPerson, Person::name)

Upvotes: 4

Related Questions