我有两个列表,我想仅包含第一个列表中没有的第二个元素的列表。问题是,我需要指定一个自定义的equal
减去时。让我们假设我想用在列表中的条目的领域之一。比方说,id
。
我实现了这种方式:
list1.filter { log -> list2.none { it.id == log.id } }
要么
val projection = logEntries.map { it.id }
list1.filter { it.id !in projection }
有没有更好的办法做到这一点?请考虑,我不能设置为类新equal
方法帐户。
你的方式做到这一点是确定的,但是当列表变得更大,你可能想要做的是:
你可以使这个过程更有效,首先把你的参考列表(list2
)一组。
val referenceIds = list2.distinctBy { it.id }.toSet()
list1.filter { it.id !in referenceIds }
背景:
你最有可能使用的ArrayList
有O(n)的时间复杂度,当你检查元素是否包含。所以,如果列表变得更大,它会需要更长的时间。
在另一方面甲HashSet
具有(1)当检查如果一个元件被包含的O一个时间复杂度。所以,如果list2
变大也不会变慢。
另一种方法?
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) }
}
输出:[0, 1, 5]
按照意见,有没有内置的方式做到这一点。 (可能不是任何根本的原因,只是因为没有人认为有必要。)
但是,您可以轻松地自己添加一个。例如,这里是你的第一个建议,转化为扩展功能:
fun <T, R> Collection<T>.minus(elements: Collection<T>, selector: (T) -> R?)
= filter{ t -> elements.none{ selector(it) == selector(t) } }
然后,您可以以同样的方式,一个内置的功能将工作称之为:
list1.minus(list2){ it.id }
(可能有更有效的实现,但是这说明了想法。)