Java 合并地图 kotlin 中的值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/54232530/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Merge values in map kotlin
提问by A.Rost
I need merge maps mapA
andmapB
with pairs of "name" - "phone number" into the final map, sticking together the values for duplicate keys, separated by commas. Duplicate values should be added only once.
I need the most idiomatic and correct in terms of language approach.
我需要将地图mapA
和mapB
“姓名”-“电话号码”对合并到最终地图中,将重复键的值粘在一起,用逗号分隔。重复值只能添加一次。我需要最惯用和正确的语言方法。
For example:
例如:
val mapA = mapOf("Emergency" to "112", "Fire department" to "101", "Police" to "102")
val mapB = mapOf("Emergency" to "911", "Police" to "102")
The final result should look like this:
最终结果应如下所示:
{"Emergency" to "112, 911", "Fire department" to "101", "Police" to "102"}
This is my function:
这是我的功能:
fun mergePhoneBooks(mapA: Map<String, String>, mapB: Map<String, String>): Map<String, String> {
val unionList: MutableMap <String, String> = mapA.toMutableMap()
unionList.forEach { (key, value) -> TODO() } // here's I can't come on with a beatiful solution
return unionList
}
采纳答案by Mtheitroada
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>
)
- 生成
Sequence
两个映射的键值对的惰性 - 由密钥组它们(结果:
Map<String, List<String>
) - 它们的值映射到逗号接合字符串(结果:
Map<String, String>
)
回答by Feedforward
I would write something like
我会写类似的东西
fun Map<String, String>.mergeWith(another: Map<String, String>): Map<String, String> {
val unionList: MutableMap<String, String> = toMutableMap()
for ((key, value) in another) {
unionList[key] = listOfNotNull(unionList[key], value).toSet().joinToString(", ")
}
return unionList
}
val mergedMap = mapA.mergeWith(mapB)
回答by Ilya E
val mapA = mapOf("Emergency" to "112", "Fire department" to "101", "Police" to "102")
val mapB = mapOf("Emergency" to "911", "Police" to "102")
val result = (mapA.entries + mapB.entries)
.groupBy({ it.key }, { it.value })
.mapValues {(_, value) ->
value.joinToString(", ")
}
回答by Sergey
Another approach:
另一种方法:
val mapA = mapOf("Emergency" to "112", "Fire department" to "101", "Police" to "102")
val mapB = mapOf("Emergency" to "911", "Police" to "102")
val result = mapA.toMutableMap()
mapB.forEach {
var value = result[it.key]
value = if (value == null || value == it.value) it.value else value + ", ${it.value}"
result[it.key] = value
}
Or using infix extension function:
或使用中缀扩展功能:
infix fun Map<String, String>.mergeWith(anotherMap: Map<String, String>): Map<String, String> {
val result = this.toMutableMap()
anotherMap.forEach {
var value = result[it.key]
value = if (value == null || value == it.value) it.value else value + ", ${it.value}"
result[it.key] = value
}
return result
}
val result = mapA mergeWith mapB
回答by s1m0nw1
Here's my solution:
这是我的解决方案:
val result = (mapA + (mapB - mapA.keys)).mapValues {
(setOf(it.value) + mapB[it.key]).filterNotNull().joinToString()
}
It creates a map of A plus the values from B that are not in A. Then it maps all values to a set and adds the value from B to that set, ultimately removing all null
values from the set and transforming it into a list, which you can use to create the desired output format.
它创建了一个 A 的映射加上 B 中不在 A 中的值。然后它将所有值映射到一个集合,并将 B 中的值添加到该集合中,最终null
从集合中删除所有值并将其转换为一个列表,其中您可以使用它来创建所需的输出格式。
回答by Roland
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:
当我查看其他解决方案时,我无法相信没有更简单的方法(或者像接受的答案一样简单的方法,而无需重新创建Map
中间新列表等)。这是我想出的 3 个(许多 ;-))解决方案:
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<String>()) { 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.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.
稍后使用键并映射值:
(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() }
使用
groupingBy
和fold
(或查看:按键分组并同时折叠每组(保持)):(mapA.asSequence() + mapB.asSequence()) .groupingBy { it.key } .fold(mutableSetOf<String>()) { accumulator, element -> accumulator.apply { add(element.value) } }
您也可以只使用一个空的
String
,并按照您需要的方式在折叠操作中连接。我的第一种方法只是使用 asequenceOf
而不是MutableSet
. 这取决于您需要什么以及您想对结果做什么。使用 Javas
Map.merge
,但忽略值中的重复项,也只是连接值:val mergedMap: Map<String, String> = mapA.toMutableMap().apply { mapB.forEach { key, value -> merge(key, value) { currentValue, addedValue -> "$currentValue, $addedValue" // just concatenate... no duplicates-check.. } } }
当然,这也可以写成不同的,但是这样我们可以确保mergedMap
Map<String, String>
在再次访问时仍然只是a 。
回答by Willi Mentzel
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()
.
- 把所有的钥匙放在一个集合中
- 迭代该集合并将每个元素与值集相关联
- 从值集中删除空值
- 使用 连接值列表中的元素
joinToString()
。
回答by Anton Kushch
In Kotlin you could do this:
在 Kotlin 中,你可以这样做:
fun main() {
val map1 = mapOf("A" to 1, "B" to 2)
val map2 = mapOf("A" to 5, "B" to 2)
val result: Map<String, Int> = listOf(map1, map2)
.fold(mapOf()) { accMap, map ->
accMap.merge(map, Int::plus)
}
println(result) // Prints: {A=6, B=4}
}
private fun <T, V> Map<T, V>.merge(another: Map<T, V>, mergeFunction: (V, V) -> V): Map<T, V> =
toMutableMap()
.apply {
another.forEach { (key, value) ->
merge(key, value, mergeFunction)
}
}
回答by Vadzim
Here is my approach with universal map-merging helper function:
这是我使用通用地图合并辅助函数的方法:
fun <K, V, R> Pair<Map<K, V>, Map<K, V>>.merge(merger: (V?, V?) -> R): Map<K, R> {
return (first.keys.asSequence() + second.keys.asSequence())
.associateWith { merger(first[it], second[it]) }
}
fun main() {
val mapA = mapOf("Emergency" to "112", "Fire department" to "101", "Police" to "102")
val mapB = mapOf("Emergency" to "911", "Police" to "102")
val result = (mapA to mapB).merge { a, b ->
listOf(a, b).filterNotNull().distinct().joinToString(",", "(", ")") }
println(result)
}
Output:
输出:
{Emergency=(112,911), Fire department=(101), Police=(102)}
{紧急=(112,911),消防部门=(101),警察=(102)}