【问题标题】:Kotlin transform List<Pair<K, Collection<V>>> into MultimapKotlin 将 List<Pair<K, Collection<V>>> 转换为 Multimap
【发布时间】:2022-01-31 01:37:32
【问题描述】:

我正在寻找一种转换成对列表的惯用方式,其中Pair.first 是键,Pair.second 是值列表。这种程序方法有效,但我希望找到一种更惯用的方法,不需要直接创建可变列表。

val pairs: Pair<String, List<Int>>

val res = mutableMapOf<String, List<Int>>()
pairs.forEach {
    res.getOrPut(it.first, ::mutableListOf).addAll(it.second)
}

这段代码可以像下面这样被封装在一个扩展函数中,但它看起来不是很通用:

fun <K, V> List<Pair<K, Collection<V>>>.toMultimap(): Map<K, List<V>> {
    var res = mutableMapOf<K, MutableList<V>>()
    forEach {
        res.getOrPut(it.first, ::mutableListOf).addAll(it.second)
    }
    return res
}

使用 pairs.toMap 不起作用,因为它会使用 last in wins 方法覆盖映射键。 groupBy 工作接近,它在列表结构的列表中创建值的键。

val pairs2 = listOf(
    Pair("a", listOf(1, 2, 3)),
    Pair("b", listOf(6, 7)),
    Pair("a", listOf(4, 5)),
    Pair("b", listOf(8, 9)),
)

val res = pairs2.groupBy({ it.first }, { it.second })
println(res)

{a=[[1, 2, 3], [4, 5]], b=[[6, 7], [8, 9]]}

然后可以展平地图,但这里的缺点是它的效率非常低,因为这会为每个键创建双倍所需的哈希图和列表(一个用于 groupby,另一个用于展平)。如果有

val res = pairs2.groupBy({ it.first }, { it.second }).mapValues { it.value.flatten() }
println(res)

{a=[1, 2, 3, 4, 5], b=[6, 7, 8, 9]}

看看是否有更好的方法来完成这种转换。

【问题讨论】:

    标签: kotlin key-value multimap


    【解决方案1】:

    不要使用groupBy,而是使用groupingBy,这会产生Grouping。这是一个中间对象,您可以在其上执行各种折叠/减少操作。在你的情况下:

    fun <K, V> List<Pair<K, Collection<V>>>.toMultimap() =
        groupingBy { it.first }
            .fold(emptyList<V>()) { acc, (_, new) -> acc + new }
    

    如果您不喜欢 + 创建太多新列表这一事实,您可以这样做:

    groupingBy { it.first }
        .fold({ _, _ -> mutableListOf<V>() }) { _, acc, (_, new) ->
            acc.addAll(new)
            acc
        }
    

    【讨论】:

      【解决方案2】:
      val pairs: List<Pair<String, List<Int>>> = listOf(
        Pair("a", listOf(1, 2, 3)),
        Pair("b", listOf(6, 7)),
        Pair("a", listOf(4, 5)),
        Pair("b", listOf(8, 9)),
      )
      
      val result = pairs
        .map { it.first }.distinct()
        .associateWith { first -> pairs.filter { it.first == first }.flatMap { it.second } }
      
      println(result)   // {a=[1, 2, 3, 4, 5], b=[6, 7, 8, 9]}
      

      【讨论】:

        猜你喜欢
        • 2011-03-06
        • 2018-11-23
        • 2019-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-13
        • 2022-01-23
        • 1970-01-01
        相关资源
        最近更新 更多