Intersection of two lists maintaining duplicate values in Kotlin

限于喜欢 提交于 2020-04-30 11:23:24

问题


I want to find the number of common elements between two lists without eliminating duplicates.

For example:


input: [1, 3, 3] & [4, 3, 3]

output: 2, since the common elements are [3, 3]


input: [1, 2, 3] & [4, 3, 3]

output: 1, since the common elements are [3]


If I were to use the Kotlin collections intersect, the result is a set, which will prevent me from counting duplicate values.

I found (for Python) this, which handles duplicates differently and this, which led me to use this implementation, where a and b are the lists:

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

However, being new to Kotlin I'm wondering if there's a more "Kotlin-y" way to do this--something taking advantage of all Kotlin's collections functionality? Maybe something that avoids explicitly iterating?


回答1:


This:

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)

will print

6

It uses the intersection of the 2 lists and by iterating through each of its items, adds to the counter the minimum number of occurrences of the item in both lists.

With this import:

import kotlin.math.min

you can avoid the creation of a list at each iteration and simplify to:

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


Courtesy of Arjan, a more elegant way to calculate the sum:

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


来源:https://stackoverflow.com/questions/53687530/intersection-of-two-lists-maintaining-duplicate-values-in-kotlin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!