35

我遇到了 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 方法吗?

列表比较的替代建议将不胜感激。

4

12 回答 12

23

仅供参考list1 == list2,如果您的自定义对象基于 a data class(它会自动为您覆盖 equals),您无需任何额外工作即可调用。

于 2019-09-02T11:56:24.090 回答
18

如果您不关心两个列表中元素的顺序,并且您的目标是检查两个列表是否具有完全相同的元素,没有任何其他元素,您可以考虑两个相互containsAll调用,例如:

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

if(list1.containsAll(list2) && list2.containsAll(list1)) {
    //both lists are of the same elements
}
于 2019-12-14T21:32:58.343 回答
16

Java列表实现equals方法,如果两个列表以相同的顺序包含相同的元素,则它们被定义为相等。我想,你在你的课上缺少equals方法。MyObject

于 2018-08-28T12:51:38.403 回答
13

使用拉链

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       
    }
}
于 2019-06-18T14:52:26.150 回答
9

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

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

于 2019-10-09T19:02:54.083 回答
7

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

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"))
于 2020-01-17T05:07:31.047 回答
1

当我想与 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)]

在调用 deleteRepeat(list1, list2) 之后

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

于 2021-04-08T16:41:01.130 回答
1

您可以使用数组和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

于 2019-09-20T08:16:58.993 回答
0

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

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
}
于 2020-12-22T18:55:51.730 回答
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
}
于 2021-03-02T08:50:29.060 回答
0

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

我已经使用在线 Kotlin 控制台对其进行了测试,结果如下: 在此处输入图像描述

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

在此处输入图像描述

于 2021-03-31T12:46:11.453 回答
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)
}
于 2018-08-28T11:00:21.883 回答