List 使用自定义相等函数减去Kotlin中的两个列表

List 使用自定义相等函数减去Kotlin中的两个列表,list,data-structures,kotlin,List,Data Structures,Kotlin,我有两个列表,我想得到只包含第一个列表中不在第二个列表中的元素的列表。问题是,在进行减法时,我需要指定一个自定义的equal。假设我想使用列表项中的一个字段。让我们说一下id 我是这样实施的: list1.filter { log -> list2.none { it.id == log.id } } 或 有更好的方法吗?请注意,我无法为类设置新的equal方法。根据注释,没有内置的方法可以做到这一点。(可能不是出于任何根本原因;只是因为没有人看到需要。) 但是,您可以自己轻松添加一个。

我有两个列表,我想得到只包含第一个列表中不在第二个列表中的元素的列表。问题是,在进行减法时,我需要指定一个自定义的
equal
。假设我想使用列表项中的一个字段。让我们说一下
id

我是这样实施的:

list1.filter { log -> list2.none { it.id == log.id } }


有更好的方法吗?请注意,我无法为类设置新的
equal
方法。

根据注释,没有内置的方法可以做到这一点。(可能不是出于任何根本原因;只是因为没有人看到需要。)

但是,您可以自己轻松添加一个。例如,下面是您的第一个建议,转换为扩展功能:

fun <T, R> Collection<T>.minus(elements: Collection<T>, selector: (T) -> R?)
    = filter{ t -> elements.none{ selector(it) == selector(t) } }
(可能有更高效的实现,但这说明了这个想法。)

另一种方法

fun main() {

    val list1 = listOf(0, 1, 2, 3, 4, 5)
    val list2 = listOf(2,3,4)

    println(list1.filterNotIn(list2))
}

fun <T> Collection<T>.filterNotIn(collection: Collection<T>): Collection<T> {
    val set = collection.toSet()
    return filterNot { set.contains(it) }
}
fun main(){
val list1=listOf(0,1,2,3,4,5)
val list2=listOf(2,3,4)
println(列表1.filterNotIn(列表2))
}
有趣的收藏。过滤器主题(收藏:收藏):收藏{
val set=collection.toSet()
返回filterNot{set.contains(it)}
}

输出:
[0,1,5]
您这样做是可以的,但是当列表变大时,您可能希望这样做:

您可以先将参考列表(
list2
)设置为一个集合,从而提高流程的效率

val referenceIds = list2.distinctBy { it.id }.toSet()

list1.filter { it.id !in referenceIds }
背景:

检查元素是否包含时,最有可能使用的
ArrayList
的时间复杂度为O(n)。因此,如果列表变大,则需要更长的时间


另一方面,当检查元素是否包含时,
HashSet
的时间复杂度为O(1)。因此,如果
list2
变得更大,它不会变慢。

看起来不错,你说的“更好”到底是什么意思?@m0skit0我希望找到Kotlin本机方法来做类似的事情,我的意思是定义一个
equal
方法,仅在运行命令时使用。我理解,类似于将lambda传递给
减号
进行比较。没有这样的事。您的案例不是常见案例,也就是说,通常您应该使用类的
equals
,而不是您自己的
equals
。我们可以简单地执行
list1-list2
。参考:@bh4r4th请阅读问题:这是关于使用自定义相等函数减去集合的问题,stdlib仍然不支持该函数。  对象自然相等的减法在stdlib中已经存在很长时间了。是的,是的,明白了。有道理。
fun main() {

    val list1 = listOf(0, 1, 2, 3, 4, 5)
    val list2 = listOf(2,3,4)

    println(list1.filterNotIn(list2))
}

fun <T> Collection<T>.filterNotIn(collection: Collection<T>): Collection<T> {
    val set = collection.toSet()
    return filterNot { set.contains(it) }
}
val referenceIds = list2.distinctBy { it.id }.toSet()

list1.filter { it.id !in referenceIds }