我需要将带有“名称”-“电话号码”对的映射mapA
和mapB
合并到最终映射中,将重复键的值粘贴在一起,并用逗号分隔。重复值只能添加一次。
就语言方法而言,我需要最惯用和正确的方法。
例如:
val mapA = mapOf("Emergency" to "112", "Fire department" to "101", "Police" to "102")
val mapB = mapOf("Emergency" to "911", "Police" to "102")
最终结果应如下所示:
{"Emergency" to "112, 911", "Fire department" to "101", "Police" to "102"}
这是我的功能:
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
}
答案 0 :(得分:5)
怎么样:
val unionList = (mapA.asSequence() + mapB.asSequence())
.distinct()
.groupBy({ it.key }, { it.value })
.mapValues { (_, values) -> values.joinToString(",") }
结果:
{Emergency=112,911, Fire department=101, Police=102}
这将:
Sequence
Map<String, List<String>
)Map<String, String>
)答案 1 :(得分:2)
我会写类似的东西
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)
答案 2 :(得分:2)
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(", ")
}
答案 3 :(得分:2)
您可以执行以下操作:
(mapA.keys + mapB.keys).associateWith {
setOf(mapA[it], mapB[it]).filterNotNull().joinToString()
}
joinToString()
连接值列表中的元素。答案 4 :(得分:2)
在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)
}
}
答案 5 :(得分:1)
另一种方法:
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
}
或使用中缀扩展功能:
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
答案 6 :(得分:1)
当我查看其他解决方案时,我不敢相信没有一种更简单的方法(或者像接受的答案一样简单的方法,而无需重新创建Map
,中间的新列表等)。 )。这是我想出的3个解决方案:(
使用键并稍后映射值:
(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
(或看看: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)
}
}
您也可以只使用一个空的String
并按照需要的方式在折叠操作中进行串联。我的第一种方法只是使用sequenceOf
而不是MutableSet
。这取决于您需要什么以及之后想要对结果做什么。
使用Java 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>
。
答案 7 :(得分:1)
一种更通用的方法(如在搜索Kotlin和合并地图时出现此帖子):
fun <K, V1, V2, R> Map<K, V1>.mergeReduce(other: Map<K, V2>, reduce: (key: K, value1: V1?, value2: V2?) -> R): Map<K, R> =
(this.keys + other.keys).associateWith { reduce(it, this[it], other[it]) }
它允许合并具有不同类型值的Map,通过自定义的reducer来增加自由度,并提高可读性。
您的问题可以解决为:
mapA.mergeReduce(mapB) { _, value1, value2 -> listOfNotNull(value1, value2).joinToString(", ") }
答案 8 :(得分:0)
这是我的解决方法:
val result = (mapA + (mapB - mapA.keys)).mapValues {
(setOf(it.value) + mapB[it.key]).filterNotNull().joinToString()
}
它将创建A的映射以及B中不在A中的值,然后将所有值映射到一个集合并将B中的值添加到该集合中,最终从该集合中删除所有null
值并将其转换为列表,您可以使用该列表创建所需的输出格式。
答案 9 :(得分:0)
这是我使用通用地图合并助手功能的方法:
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)
}
输出:
{紧急情况=(112,911),消防队=(101),警察=(102)}
答案 10 :(得分:-1)
(mapA.data.asSequence() + mapB.asSequence())
.map { Pair(it.key, it.value) }
.toMap()