Merge values in map kotlin
You can do the following:
(mapA.keys + mapB.keys).associateWith {
setOf(mapA[it], mapB[it]).filterNotNull().joinToString()
}
- put all keys in a set
- iterate over that set and and associate each element with the set of values
- remove the null values from the value set
- concatenate the elements in the value list using
joinToString()
.
How about:
val unionList = (mapA.asSequence() + mapB.asSequence())
.distinct()
.groupBy({ it.key }, { it.value })
.mapValues { (_, values) -> values.joinToString(",") }
Result:
{Emergency=112,911, Fire department=101, Police=102}
This will:
- produce a lazy
Sequence
of both maps' key-value pairs - group them by key (result:
Map<String, List<String>
) - map their values to comma-joined strings (result:
Map<String, String>
)
While I looked at the other solutions I couldn't believe that there isn't an easier way (or ways as easy as the accepted answer without the need to recreate a Map
, intermediate new lists, etc.). Here are 3 (of many ;-)) solutions I came up with:
Using the keys and mapping the values later:
(mapA.keys.asSequence() + mapB.keys) .associateWith { sequenceOf(mapA[it], mapB[it]) // one of the sides may have null values in it (i.e. no entry in the map)... .filterNotNull() .distinct() .toList() // or if you require/prefer, do the following instead: joinToString() }
Using
groupingBy
andfold
(or have a look at: Group by key and fold each group simultaneously (KEEP)):(mapA.asSequence() + mapB.asSequence()) .groupingBy { it.key } .fold({ _, _ -> mutableSetOf() }) { _, accumulator, element -> accumulator.apply { add(element.value) } }
You could also just use an empty
String
instead and concatenate in the fold operation the way you need it. My first approach just used asequenceOf
instead of theMutableSet
. It depends on what you require and what you want to do with the result afterwards. Be sure to use the overloadedfold
-function that accepts an initial value selector, which creates a new initial value every time a new key is encountered. Thanks xzt for noting it.Using Javas
Map.merge
, but ignoring duplicates in the value and also just concatenating the values:val mergedMap: Map<String, String> = mapA.toMutableMap().apply { mapB.forEach { key, value -> merge(key, value) { currentValue, addedValue -> "$currentValue, $addedValue" // just concatenate... no duplicates-check.. } } }
This, of course, can also be written differently, but this way we ensure that mergedMap is still just a
Map<String, String>
when accessed again.