在 Kotlin 中维护重复值的两个列表的交集

Mic*_*iyo 2 collections kotlin

我想在不消除重复项的情况下找到两个列表之间的公共元素的数量。

例如:


输入:[1, 3, 3]&[4, 3, 3]

输出:2,因为公共元素是[3, 3]


输入:[1, 2, 3]&[4, 3, 3]

输出:1,因为公共元素是[3]


如果我要使用 Kotlin 集合intersect,结果是一个集合,这将阻止我计算重复值。

我发现(对于 Python)this,它以不同的方式处理重复项和this,这使我使用了这个实现,列表在哪里a和b在哪里:

val aCounts = a.groupingBy { it }.eachCount()
val bCounts = b.groupingBy { it }.eachCount()
var intersectionCount = 0;
for ((k, v) in aCounts) {
    intersectionCount += Math.min(v, bCounts.getOrDefault(k, 0))
}
Run Code Online (Sandbox Code Playgroud)

然而,作为 Kotlin 的新手,我想知道是否有一种更“Kotlin-y”的方式来做到这一点——利用 Kotlin 的所有集合功能的东西?也许避免显式迭代的东西?

for*_*pas 8

这个:

val a = listOf(1, 2, 3, 3, 4, 5, 5, 5, 6)
val b = listOf(1, 3, 3, 3, 4, 4, 5, 6, 6, 7)

var counter = 0

a.intersect(b).forEach { x -> counter += listOf(a.count {it == x}, b.count {it == x}).min()!! }

println(counter)
Run Code Online (Sandbox Code Playgroud)

将打印

6
Run Code Online (Sandbox Code Playgroud)

它使用两个列表的交集,并通过迭代其每个项目,将两个列表中项目出现的最小次数添加到计数器中。

有了这个导入:

import kotlin.math.min
Run Code Online (Sandbox Code Playgroud)

您可以避免在每次迭代时创建列表并简化为:

a.intersect(b).forEach { x-> counter += min(a.count {it == x}, b.count {it == x}) } 
Run Code Online (Sandbox Code Playgroud)


由 Arjan 提供,这是一种更优雅的计算总和的方法:

val result = a.intersect(b).map { x -> min(a.count {it == x}, b.count {it == x}) }.sum()
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

7799 次

最近记录:

5 年,9 月 前