简体   繁体   English

Kotlin 变换列表<pair<k, collection<v> &gt;&gt; 进入多图</pair<k,>

[英]Kotlin transform List<Pair<K, Collection<V>>> into Multimap

I'm looking for an idiomatic way of converting a list of pairs where Pair.first is a key and Pair.second is a list of values.我正在寻找一种转换成对列表的惯用方法,其中Pair.first是键, Pair.second是值列表。 This procedural approach works but I was hoping to find a more idiomatic way that doesn't require creating the mutable lists directly.这种程序方法有效,但我希望找到一种更惯用的方法,不需要直接创建可变列表。

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

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

This code can get wrapped in an extension function like follows but it doesn't seem very generic:此代码可以包含在扩展 function 中,如下所示,但它似乎不是很通用:

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
}

Using pairs.toMap doesn't work because it overwrites map keys with a last in wins approach.使用pairs.toMap不起作用,因为它用最后一次获胜的方法覆盖了map 键。 groupBy works comes close, it creates keys to values in a list of lists structure. 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]]} {a=[[1, 2, 3], [4, 5]], b=[[6, 7], [8, 9]]}

It is possible to then flatten the map but the downside here is that its pretty inefficient as this creates double the required hashmaps and lists per key (one for groupby and another for flatten).然后可以展平 map,但这里的缺点是它的效率非常低,因为这会为每个键创建双倍所需的哈希图和列表(一个用于 groupby,另一个用于展平)。 If there如果有

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]} {a=[1, 2, 3, 4, 5], b=[6, 7, 8, 9]}

Looking to see if there are any better approaches to accomplishing this transform.看看是否有更好的方法来完成这种转换。

Rather than groupBy , use groupingBy , which produces a Grouping .而不是groupBy ,使用groupingBy ,它产生一个Grouping This is an intermediate object on which you can do all kinds of fold/reduce operations.这是一个中间 object,您可以在其上执行各种折叠/减少操作。 In your case:在你的情况下:

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

If you don't like the fact that + creates too many new lists, you can do something like this:如果你不喜欢+创建太多新列表的事实,你可以这样做:

groupingBy { it.first }
    .fold({ _, _ -> mutableListOf<V>() }) { _, acc, (_, new) ->
        acc.addAll(new)
        acc
    }
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]}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM