比较Kotlin中的两个列表

时间:2018-08-28 09:09:08

标签: java kotlin kotlin-interop

我遇到了kotlin equals函数来比较两个相同类型的列表。它对于带有数据类的纯Kotlin很好用。

我在Kotlin项目中使用Java库,其中的回调方法以X秒的时间间隔返回对象列表。尝试针对每个调用将旧列表与新列表进行比较,但是即使项目相同且相等,equals也会返回false。

val mOldList: MutableList<MyObject>()? = null

override fun updatedList(list: MutableList<MyObject>){
    // other code
    if (mOldList.equals(list)) // false everytime
}

这是因为Java的来自库的equals方法吗?

列表比较的替代建议将是有益的。

12 个答案:

答案 0 :(得分:2)

Java列表实现equals方法,并且如果两个列表包含相同顺序的相同元素,则两个列表定义为相等。我猜想,您的equals类中缺少MyObject方法。

答案 1 :(得分:2)

:使用扩展功能的简短版本:

fun List<*>.deepEquals(other : List<*>) = 
    this.size == other.size && this.mapIndexed { index, element -> element == other[index] }.all { it }

您可以这样使用它:

listOf("Hola", "Mundo").deepEquals(listOf("Hello", "World"))

答案 2 :(得分:1)

您可以使用以下实现比较两个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
}

或忽略订单变体:

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
}

注意:这两个函数仅比较第一级深度

答案 3 :(得分:1)

如果您不必担心两个列表中元素的顺序,而您的目标是只检查两个列表中元素完全相同,没有其他元素,则可以考虑两个相互containsAll的调用,例如:

var list1 = mutableListOf<String>()
var list2 = mutableListOf<String>()

if(list1.containsAll(list2) && list2.containsAll(list1)) {
    //both lists are of the same elements
}

答案 4 :(得分:0)

您可以遍历一个列表并从第二个列表中检查相应的位置值。请以下面的示例为参考。

var list1 = mutableListOf<String>()
var list2 = mutableListOf<String>()

list1.forEachIndexed { i, value ->
    if (list2[i] == value)
    {
        // your implementaion
    }  
}

此外,您还可以过滤列表以获取更改的值。

var list1 = mutableListOf<String>()
var list2 = mutableListOf<String>()

val changedList = list1.filterIndexed { i, value -> 
    list2[i] != value)
}

答案 5 :(得分:0)

使用zip

  

zip返回一个从该数组的元素和另一个具有相同索引的数组构建的对的列表。返回的列表具有最短集合的长度。

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       
    }
}

答案 6 :(得分:0)

如果您的自定义对象基于list1 == list2(它会自动覆盖您的等号),您也可以无需任何额外的工作就可以调用data class

答案 7 :(得分:0)

您可以使用数组和contentDeepEquals

infix fun <T> Array<out T>.contentDeepEquals(
    other: Array<out T>
): Boolean
JVM
1.1
@JvmName("contentDeepEqualsInline") infix fun <T> Array<out T>.contentDeepEquals(
    other: Array<out T>
): Boolean

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/content-deep-equals.html

答案 8 :(得分:0)

到目前为止的问题和答案主要集中在 equals/!equals 上,但由于标题谈到比较,我将给出一个稍微通用的答案,实现 compareTo 为 <、= 返回 -1,0,1, >

fun <T: Comparable<T>> Iterable<T>.compareTo(other: Iterable<T>): Int {
    val otherI = other.iterator()
    for (e in this) {
        if (!otherI.hasNext()) return 1 // other has run out of elements, so `this` is larger
        val c = e.compareTo(otherI.next())
        if (c != 0) return c // found a position with a difference
    }
    if (otherI.hasNext()) return -1 // `this` has run out of elements, but other has some more, so other is larger
    return 0 // they're the same
}

答案 9 :(得分:0)

如果您想比较两个列表,它们具有相同数量的相同元素,并且不关心顺序,则另一个答案:

infix fun <T> List<T>.elementEquals(other: List<T>): Boolean {
  if (this.size != other.size) return false

  val tracker = BooleanArray(this.size)
  var counter = 0

  root@ for (value in this) {
    destination@ for ((i, o) in other.withIndex()) {
      if (tracker[i]) {
        continue@destination
      } else if (value?.equals(o) == true) {
        counter++
        tracker[i] = true
        continue@root
      }
    }
  }

  return counter == this.size
}

答案 10 :(得分:0)

想说 containsAll() 比排序和检查相等要慢得多。

我使用在线 Kotlin 控制台对其进行了测试,结果如下: enter image description here

但最快的方法可能是使用 Set 代替。 (但是,set 不允许重复元素。所以要小心你的用例)

enter image description here

答案 11 :(得分:0)

当我想与 kotlin 上的列表进行比较时,我喜欢这种方式

data class Element(val id: String, val name: String)
var list1 = mutableListOf<Element>()
var list2 = mutableListOf<Element>()
fun deleteRepeated(
        list1: List<Element>,
        newElementsList: List<Element>
    ): List<FileInfo> {
        return list2.filterNot { isTheSameID(it, list1) }
 }
 private fun isTheSameID(element: Element, list1: List<FileInfo>): Boolean {
     list1.forEach {
         if (element.id == it.id){
             return true
         }
     }
     return false
 }

list1 = [(id=1, name=Eva),(id=2, name=Ana), id=3, name=Abraham)]

list2 = [(id=2, name=Ana), id=3, name=Abraham)]

调用deleteRepeated(list1, list2)后

list1 = [(id=1, name=Eva)]