First, I have to say that I don’t think that this a complete solution for comparing two lists ignoring order - because it does not handle duplicates correctly. It checks only for the number of duplicates, but not whether it is the same duplicates, e.g.
fun main() {
val list1 = listOf(1,1,2)
val list2 = listOf(1,2,2)
print("Are these lists equal ignoring order? ")
println(list1.size == list2.size && list1.toSet() == list2.toSet()) // true
}
One could say that duplicates are irrelevant, but why would you check for their total number then?
===
Now to the actual problem: The source uses the set transformation to stay in linear complexity. For that it uses the constant complexity of set lookup which relies on equal elements having the same hash value.
If you want to compare by only a part of the properties (presumably without changing the types themselves, i.e. modifying their hash value method to only be based on these comparing properties), you can compare to sets with substitute objects:
/// ignores duplicates and order of elements.
fun <T, U> List<T>.myEquals(other: List<T>, compareBy: (T) -> U): Boolean {
return map(compareBy).toSet() == other.map(compareBy).toSet()
}
Here some sample calls to the method:
fun main() {
val list1 = listOf(Pair("Important", "Ignore this!"))
val list2 = listOf(Pair("Important", "Ignore that too!"))
println("Are these lists equal ignoring order and duplicates? ")
println(list1.myEquals(list2, { it.first })) // true
println(list1.myEquals(list2, { listOf(it.second, it.first) })) // false
val list3 = listOf(Pair("Different value", "Ignore this!"))
println(list1.myEquals(list3, { it.first })) // false
}
Note: The substitute object can be anything you want - it only needs to have a correct hash implementation.
The method would also work for Collection<T>
instead of List<T>
and you maybe want to give it a better name than myEquals
.
Live long and prosper,
Tlin47