Comparing two lists in kotlin
Solution 1
Just fyi you can call list1 == list2
without any extra work, if your custom object is based off of a data class
(which automatically overrides equals for you).
Solution 2
If you don't bother about order of elements in both lists, and your goal is to just check that two lists are of exactly same elements, without any others, you can consider two mutual containsAll
calls like:
var list1 = mutableListOf<String>()
var list2 = mutableListOf<String>()
if(list1.containsAll(list2) && list2.containsAll(list1)) {
//both lists are of the same elements
}
Solution 3
Java lists implement equals
method and two lists are defined to be equal if they contain the same elements in the same order. I guess, you are missing equals
method in your MyObject
class.
Solution 4
Using zip
zip
returns a list of pairs built from the elements of this array and the other array with the same index. The returned list has length of the shortest collection.
fun listsEqual(list1: List<Any>, list2: List<Any>): Boolean {
if (list1.size != list2.size)
return false
val pairList = list1.zip(list2)
return pairList.all { (elt1, elt2) ->
elt1 == elt2
}
}
Solution 5
You can use implementations below for comparing of two Collection
:
infix fun <T> Collection<T>.deepEqualTo(other: Collection<T>): Boolean {
// check collections aren't same
if (this !== other) {
// fast check of sizes
if (this.size != other.size) return false
val areNotEqual = this.asSequence()
.zip(other.asSequence())
// check this and other contains same elements at position
.map { (fromThis, fromOther) -> fromThis == fromOther }
// searching for first negative answer
.contains(false)
if (areNotEqual) return false
}
// collections are same or they are contains same elements with same order
return true
}
Or order ignore variant:
infix fun <T> Collection<T>.deepEqualToIgnoreOrder(other: Collection<T>): Boolean {
// check collections aren't same
if (this !== other) {
// fast check of sizes
if (this.size != other.size) return false
val areNotEqual = this.asSequence()
// check other contains next element from this
.map { it in other }
// searching for first negative answer
.contains(false)
if (areNotEqual) return false
}
// collections are same or they are contains same elements
return true
}
Note: both function compare only first level of deep
Comments
-
Aswin almost 2 years
I came across with kotlin equals function to compare two list of same type. It works fine for pure Kotlin with data classes.
I'am using a Java library in Kotlin project in which a callback method returns a list of objects for a time interval of X seconds. Trying to compare the old list with new list for every call, but equals returns false even the items are same and equal.
val mOldList: MutableList<MyObject>()? = null override fun updatedList(list: MutableList<MyObject>){ // other code if (mOldList.equals(list)) // false everytime }
Is this because of Java's equals method from library?
Alternative suggestions for list compare would be appreciative.
-
Aswin over 5 years
MyObject
is a class from library, so I cannot overrideequals()
method. -
Henry about 5 yearsYou could always extend
MyObject
and then overrideequals()
, if possible. -
Hola Soy Edu Feliz Navidad over 4 yearsThat's the most logical answer.
-
shabunc over 4 yearsI'm downvoting this - this is definitely not the best way to do it.
-
DruidKuma over 4 years@shabunc Could you please state what is wrong about this way?
-
shabunc over 4 years@DruidKuma because instead of O(n) comparisons you basically calling containsAll twice and this just can not have better performance than linear comparison per index. - check this for instance - stackoverflow.com/questions/10199772/…
-
Dilroop Singh about 4 yearsanswer mentions if you dont bother the order of elements
-
Jakob Ulbrich almost 4 yearsTo break early and avoid iterating over the whole list, you should use
this.asSequence().mapIndexed {...}
-
Manushin Igor almost 4 yearsThis method allocates several unnesesary objects: at least one new list and new Pair per each element from the longest list. In addition several enumerators are allocated, however JIT can put them on stack. So this method requires O(N) additional memory in heap.
-
Manushin Igor almost 4 yearsThis method can fail if lists have different sizes. Also this method allocates new list in memory.
-
amynbe almost 4 yearsGood point. In that regard, @XIII-th 's answer below is better stackoverflow.com/a/58310635/326162
-
Manushin Igor almost 4 yearsSecond answer has O(N^2) complexity. Statement
it in other
has O(N) complexity for list and it is called N times. Right solution for second case is something likereturn this.toSet() == other.toSet()
-
Sergei Bubenshchikov almost 4 years@ManushinIgor yes, your solution is better the thаn my. Thanks
-
Manushin Igor almost 4 yearsInstead of
List
,Set
should be used.HashSet
(notTreeSet
- it is important) collections have O(1) lookup complexity (list have O(N)). So just replace bothmutableListOf
tomutableSetOf
. -
Manushin Igor almost 4 yearsPlease note, that this function requires the same elements order for
true
answer. -
handhand over 3 yearsIf there are no duplicates in your list, you can compare the sizes first, then one containsAll() will be enough.
-
Sai over 3 yearsThanks. And for the people who wonder about this
listOfdataClass1.map { it.string } == listOfdataClass2.map { it.string }
also works as expected. -
Sira Lam about 3 yearsPerformance wise,
containsAll()
is very slow. Sort and check equals is way faster. -
Salim Mazari Boufares over 2 yearsThis won't work if the elements don't have the same order, an option is to sort both lists before to compare them.
-
Farid over 2 yearsYeah, easy-peasy. What happens if MyObject is final?
-
Dakshinamurthy Karra over 2 yearsUse a decorator?