m.reiter
m.reiter

Reputation: 2525

Idiomatic way to check if some (not all) properties of two objects equal in Kotlin

Let's assume i have a class with two instances:

class Car(val id: Int, val color: Color, val pistons: Int, val spoiler: Boolean)

val audi = Car(1234, Color.BLUE, 8, false)
val bmw = Car(4321, Color.WHITE, 6, false)

Now i'd like to check equality for some properties (not all -> i'd use a data class in that case)

fun looksSimilar(a: Car, b: Car) = a.color == b.color && a.spoiler == b.spoiler

I'm now looking for a method which does comparison:


I've come up with the following proposal:

fun <T> Pair<T, T>.equalIn(vararg arguments: (T) -> Any?) =
    arguments.toList().all { it(first) == it(second) }

which allows me to write the above check as

val looksSimilar = (audi to bmw).equalIn({it.color}, {it.spoiler})

Does anyone know a better (e.g. cleaner/faster) solution?


My usecase is the following:

I'm writing an Android App with multiple RecyclerView's (= fancy view to display lists)

Each RecyclerView has a ListAdapter (responsible for the underlying list)

Each ListAdapter requires a DiffUtil.ItemCallback (for comparing old & new Items & initiating appropiate changes in the view)

val callback = object : DiffUtil.ItemCallback<Car>() {

    override fun areItemsTheSame(oldItem: Car, newItem: Car): Boolean
    // usually checks for id, e.g. oldItem.id == newItem.id

    override fun areContentsTheSame(oldItem: Car, newItem: Car): Boolean
    // checks if two items look the same.
    // Used for fancy enter/exit animations afaik.
    // e.g. (oldItem to newItem).equalIn({it.color}, {it.spoiler})
}

Upvotes: 3

Views: 1267

Answers (1)

vatbub
vatbub

Reputation: 3109

While browsing by StackOverflow history, I found this question again and it tickled my brain, so I thought about it a little. I still stand by my opinion that I prefer explicit if checks (easier to understand IMO, fastest performance), but if I had to do it with an extension function, I would rather use a list instead of a pair (allowing for more than two inputs) and I would use reference syntax for the lambdas at the call site, making it a little more concise:

fun <T> List<T>.equalIn(vararg arguments: (T) -> Any?): Boolean {
    if (isEmpty()) return false
    val argumentsList = arguments.toList()
    return all { item -> argumentsList.all { it(item) == it(first()) } }
}

fun main() {
    val audi = Car(1234, Color.BLUE, 8, false)
    val bmw = Car(4321, Color.BLUE, 6, false)
    println(listOf(audi, bmw).equalIn(Car::color, Car::spoiler))
}

Upvotes: 2

Related Questions