Necesito fusionar los mapas mapA
y mapB
con pares de "nombre" - "número de teléfono" en el mapa final, juntando los valores de las claves duplicadas, separados por comas. Los valores duplicados deben agregarse solo una vez. Necesito el enfoque más idiomático y correcto en términos de lenguaje.
Por ejemplo:
val mapA = mapOf("Emergency" to "112", "Fire department" to "101", "Police" to "102") val mapB = mapOf("Emergency" to "911", "Police" to "102")
El resultado final debería verse así:
{"Emergency" to "112, 911", "Fire department" to "101", "Police" to "102"}
Esta es mi función:
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 }
Qué tal si:
val unionList = (mapA.asSequence() + mapB.asSequence()) .distinct() .groupBy({ it.key }, { it.value }) .mapValues { (_, values) -> values.joinToString(",") }
Resultado:
{Emergency=112,911, Fire department=101, Police=102}
Esta voluntad:
Sequence
perezosa de los pares clave-valor de ambos mapasMap<String, List<String>
)Map<String, String>
)Puedes hacer lo siguiente:
(mapA.keys + mapB.keys).associateWith { setOf(mapA[it], mapB[it]).filterNotNull().joinToString() }
joinToString()
.Mientras miraba las otras soluciones, no podía creer que no haya una manera más fácil (o formas tan fáciles como la respuesta aceptada sin la necesidad de recrear un Map
, nuevas listas intermedias, etc.). Aquí hay 3 (de muchas ;-)) soluciones que se me ocurrieron:
Usando las claves y mapeando los valores más tarde:
(mapA.keys.asSequence() + mapB.keys) .associateWith { sequenceOf(mapA[it], mapB[it]) // one of the sides may have null values in it (ie no entry in the map)... .filterNotNull() .distinct() .toList() // or if you require/prefer, do the following instead: joinToString() }
Usando groupingBy
y fold
(o eche un vistazo a: Group by key y fold cada grupo simultáneamente (KEEP) ):
(mapA.asSequence() + mapB.asSequence()) .groupingBy { it.key } .fold({ _, _ -> mutableSetOf() }) { _, accumulator, element -> accumulator.apply { add(element.value) } }
También podría usar una String
vacía en su lugar y concatenar en la operación de plegado de la manera que lo necesite. Mi primer enfoque solo usó una sequenceOf
de en lugar de MutableSet
. Depende de lo que necesites y de lo que quieras hacer con el resultado después. Asegúrese de utilizar la función de fold
sobrecargada que acepta un selector de valor inicial, que crea un nuevo valor inicial cada vez que se encuentra una nueva clave. Gracias xzt por notarlo.
Usando Javas Map.merge
, pero ignorando los duplicados en el valor y también simplemente concatenando los valores:
val mergedMap: Map<String, String> = mapA.toMutableMap().apply { mapB.forEach { key, value -> merge(key, value) { currentValue, addedValue -> "$currentValue, $addedValue" // just concatenate... no duplicates-check.. } } }
Esto, por supuesto, también se puede escribir de manera diferente, pero de esta manera nos aseguramos de que mergedMap siga siendo solo Map<String, String>
cuando se accede de nuevo.