Kotlin - from a list of Maps, to a map grouped by key

南笙酒味 提交于 2020-12-31 04:41:58

问题


I have a List<Map<Branch,Pair<String, Any>>> that I would like to convert in a single Map<Branch,List<Pair<String, Any>>> .

So if I have an initial list with simply 2 elements :

List

1. branch1 -> Pair(key1,value1)

   branch2 -> Pair(key2,value2)


2. branch1 -> Pair(key1a,value1a)

I want to end up with :

Map

branch1 -> Pair(key1,value1)

           Pair(key1a,value1a)

branch2 -> Pair(key2,value2)

so a kind of groupBy, using all the values of the keys in the initially nested maps..

I have tried with

list.groupBy{it-> it.keys.first()} 

but obviously it doesn't work, as it uses only the first key. I want the same, but using all keys as individual values.

What is the most idiomatic way of doing this in Kotlin ? I have an ugly looking working version in Java, but I am quite sure Kotlin has a nice way of doing it.. it's just that I am not finding it so far !

Any idea ?

Thanks


回答1:


The following:

val result =
    listOfMaps.asSequence()
        .flatMap {
          it.asSequence()
        }.groupBy({ it.key }, { it.value })

will give you the result of type Map<Branch,List<Pair<String, Any>>> with the contents you requested.




回答2:


val list: List<Map<Branch, Pair<String, Any>>> = listOf() 
val map = list
    .flatMap { it.entries }
    .groupBy { it.key }
    .mapValues { entry -> entry.value.map { it.value } }



回答3:


I've managed to write this.

data class Branch(val name: String)
data class Key(val name: String)
data class Value(val name: String)


val sharedBranch = Branch("1")
val listOfMaps: List<Map<Branch, Pair<Key, Value>>> = listOf(
        mapOf(sharedBranch to Pair(Key("1"), Value("1")),
                Branch("2") to Pair(Key("2"), Value("2"))),
        mapOf(sharedBranch to Pair(Key("1a"), Value("1a")))
)

val mapValues: Map<Branch, List<Pair<Key, Value>>> = listOfMaps.asSequence()
        .flatMap { map -> map.entries.asSequence() }
        .groupBy(Map.Entry<Branch, Pair<Key, Value>>::key)
        .mapValues { it.value.map(Map.Entry<Branch, Pair<Key, Value>>::value) }

println(mapValues)

Is it appliable for your needs?




回答4:


Extract it to an extension function

private fun <K, V> List<Map<K, V>>.group(): Map<K, List<V>> =
        asSequence().flatMap { it.asSequence() }.groupBy({ it.key }, { it.value })

Use it like so:

val list = yourListOfMaps
val grouped = list.group()



回答5:


Everyone else is using flatMap, but you can also consider using fold, which is a common operation for reducing a larger collection into a smaller one. (For example, you can fold a list of integers into a single sum; here, a list of maps into a single map).

Perhaps others will find this easier to read than the flatMap versions above:

val listOfMaps: List<Map<Key, Value>> = ...

val mergedMaps: Map<Key, List<Value>> = 
  listOfMaps
    .fold(mutableMapOf()) { acc, curr ->
      curr.forEach { entry -> acc.merge(entry.key, listOf(entry.value)) { new, old -> new + old } }
      acc
    }

What the above code is doing:

  • Create a new, empty map. This will be acc (that is, the accumulator).
  • Iterate through our list of maps.
  • Work on one map (curr) at a time.
  • For the current map, run over each of its key/value pairs.
  • For each key/value, call merge on acc, passing in a list of size one (wrapping the value). If nothing is associated with the key yet, that list is added; otherwise, it is appended to the list already there.
  • Return the accumulating map, so it's used again in the next step.


来源:https://stackoverflow.com/questions/53433108/kotlin-from-a-list-of-maps-to-a-map-grouped-by-key

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