Me gustaría fusionar dos mapas anidados como se muestra a continuación, sin sobrescribir los datos de los valores del mapa externo, o reemplazando el mapa interno y sobrescribiendo los datos que ya están allí.
Idealmente, dentro del mapa anidado, mantendría los pares clave/valor que ya tengo y los agregaría con el segundo mapa.
val mapOne: MutableMap<String, MutableMap<String, String>> = mutableMapOf( "DirectoryOne" to mutableMapOf( "FeatureOne" to "SomeUniqueStringFeature1", "FeatureTwo" to "SomeUniqueStringFeature2" ) ) val mapTwo: MutableMap<String, MutableMap<String, String>> = mutableMapOf( "DirectoryOne" to mutableMapOf( "FeatureThree" to "SomeUniqueStringFeature3" ) )El resultado que necesito sería el siguiente:
val mapOne: MutableMap<String, MutableMap<String, String>> = mutableMapOf( "DirectoryOne" to mutableMapOf( "FeatureOne" to "SomeUniqueStringFeature1", "FeatureTwo" to "SomeUniqueStringFeature2", "FeatureThree" to "SomeUniqueStringFeature3" ) )Solo para elaborar un poco el razonamiento detrás de esto. Estoy planeando construir el mapa dinámicamente en tiempo de ejecución y agregar funciones a un solo mapa, ya que deben agregarse durante la duración de la aplicación.
Pude realizar la acción deseada con el siguiente código. Iterando sobre los pares de clave/valor externos y fusionando los pares de clave/valor anidados con un BiConsumer/BiFunction para mapOne. (Escribir se volvió un poco pesado)
mapTwo.forEach(BiConsumer { k: String, v: MutableMap<String, String> -> mapOne.merge(k, v, BiFunction { v1: MutableMap<String, String>, v2: MutableMap<String, String> -> v1.putAll(v2) v1 }) })Pronto descubrí que podía emplear más fácilmente una lambda (eliminación de BiConsumer/BiFunction) y luego sacar la lambda del paréntesis de combinación. La solución óptima final se muestra a continuación.
mapTwo.forEach { (k: String, v: MutableMap<String, String>) -> mapOne.merge(k, v ) { v1: MutableMap<String, String>, v2: MutableMap<String, String> -> v1.putAll(v2) v1 } }Estoy envolviendo el fragmento anterior en una función/método para poder aplicar esto varias veces cuando sea necesario.
Si desea evitar el uso incómodo de la función de combinación de Java 8, puede usar getOrPut . Esto también es más eficiente debido a la función en línea.
Además, de acuerdo con las convenciones de codificación de Kotlin , es preferible usar un bucle for normal en lugar de forEach (a menos que lo esté llamando en un operador anulable o al final de una cadena de operadores de colección).
for ((key, map) in mapTwo) { mapOne.getOrPut(key, ::mutableMapOf).putAll(map) }Generalizado:
fun <K1, K2, V> MutableMap<in K1, MutableMap<K2, V>>.mergeIn(other: Map<out K1, Map<out K2, V>>) { for ((key, map) in other) { getOrPut(key, ::mutableMapOf).putAll(map) } }