【问题标题】:Intersection of two lists maintaining duplicate values in Kotlin在 Kotlin 中维护重复值的两个列表的交集
【发布时间】:2021-01-09 14:55:15
【问题描述】:

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

例如:


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

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


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

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


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

我发现(对于 Python)this,它以不同方式处理重复项和 this,这导致我使用 this 实现,其中 ab 是列表:

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

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

【问题讨论】:

    标签: collections kotlin


    【解决方案1】:

    这个:

    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)
    

    将打印

    6
    

    它使用 2 个列表的交集并通过遍历其中的每个项目,向计数器添加项目在两个列表中的最小出现次数。

    通过此导入:

    import kotlin.math.min
    

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

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


    由 Arjan 提供,一种更优雅的求和方式:

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

    【讨论】:

    • 它可以做得更短,不需要计数器变量:val result = a.intersect(b).map { x -> min(a.count {it == x}, b.count {it == x}) }.sum()
    • 我同意它更优雅,但性能是一样的。无论如何,你想让我把它包括在答案中吗(我当然会提到你)。
    • 当然,您可以在回答中提及。一个好处是它只使用值,而不是可能意外更改的变量。并且因为它不使用单独的结果值,它还允许我们创建一个 oneliner 函数。 Kotlin 的美女之一,imo。
    • 这就是为什么我认为它更优雅。
    • 有趣,谢谢!它确实有迭代ab 以查找a.intersect(b) 中每个元素的计数的缺点。例如,如果 ab 在 0 和 100000 之间保存 100000 个随机整数,则原始问题中的方法需要
    【解决方案2】:

    从两个或多个数组列表中获取公共元素

    输入

    • a = {1, 2, 2, 4, 5, 6}
    • b = {1、2、2、4、5、6}
    • c = {1, 2, 2, 4, 6}

    输出 = {1, 2, 2, 4, 6}

    fun main() {
    
    val array = ArrayList<ArrayList<String>>()
    
    val arr1 = arrayListOf("1", "2", "2", "4", "5", "6")
    val arr2 = arrayListOf("1", "2", "2", "4", "5", "6")
    val arr3 = arrayListOf("1", "2", "2", "4", "6")
    
    array.add(arr1)
    array.add(arr2)
    array.add(arr3)
    
    
    println(getCommonElements(array)) }
    

    创建一个数据类,用于存储arrayIndex和elementIndex

    internal class IndexArray(val arrayIndex: Int,
                          val elementIndex: Int)
    

    获取公共元素的算法

    fun getCommonElements(arrayList: ArrayList<ArrayList<String>>): ArrayList<String> {
    
    val commonElements = ArrayList<String>()
    var isContain = true
    val firstArray = arrayList[0]
    
    val indexArray = ArrayList<IndexArray>()
    
    // for loop for firstArray
    for (e in firstArray) {
    
        var elementIndex: Int
        var arrayIndex: Int
    
        // for loop for next ArrayList
        for (i in 1 until arrayList.size) {
    
            if (!arrayList[i].contains(e)) {
                isContain = false
                break
    
            } else {
                elementIndex = arrayList[i].indexOf(e)
                arrayIndex = i
    
                indexArray.add(IndexArray(arrayIndex, elementIndex))
            }
        }
    
        if (isContain) {
            commonElements.add(e)
    
            // remove element
            for (i in 0 until indexArray.size) {
                arrayList[indexArray[i].arrayIndex].removeAt(indexArray[i].elementIndex)
            }
    
            indexArray.clear()
    
        } else {
            indexArray.clear()
            isContain = true
        }
    
    
    }
    
    return commonElements }
    

    【讨论】:

      猜你喜欢
      • 2020-05-31
      • 1970-01-01
      • 2015-06-27
      • 1970-01-01
      • 2014-12-27
      • 2013-08-29
      • 1970-01-01
      • 2015-10-16
      相关资源
      最近更新 更多