2012-04-12 34 views

Respuesta

15

Sin embargo, otra solución sería ser:

def m1 = [ a:1, b:2 ] 
def m2 = [ b:1, c:3 ] 

def newMap = [m1,m2]*.keySet().flatten().unique().collectEntries { 
    [ (it): [m1,m2]*.get(it).findAll().sum() ] 
} 

Tomando epidemian's answer como inspiriation, también puede escribir un método para manejar múltiples mapas

def m1 = [a: 1, b: 2] 
def m2 = [b: 1, c: 3] 

def combine(Map... m) { 
    m.collectMany { it.entrySet() }.inject([:]) { result, e -> 
    result << [ (e.key):e.value + (result[ e.key ] ?: 0) ] 
    } 
} 

def newMap = combine(m1, m2) 
+3

creo que proporciona un método completo con una buena firma como el segundo ejemplo (en lugar de la expresión lanzada en el aire) realmente agrega un poco a la calidad general de la respuesta, porque así es como deberíamos escribir este tipo de cosas en código "real" si nos preocupamos por la calidad del código. +1 = D – epidemian

2

No creo que hay un método ya preparado para esto, tal vez usar algo como:

def m1 = [a: 1, b: 2] 
def m2 = [b: 1, c: 3] 
def newMap = (m1.keySet() + m2.keySet()).inject([:]) { 
    acc, k -> acc[k] = (m1[k] ?: 0) + (m2[k] ?: 0); acc 
} 
0

Esto lo hace:

Map additionJoin(Map map1, Map map2) 
{ 
    def result = [:]; 
    result.putAll(map1); 
    result.putAll(map2); 

    result.each { key, value -> 
    if(map1[key] && map2[key]) 
    { 
     result[key] = map1[key] + map2[key] 
    } 
    } 

    return result; 
} 

def a = [a: 1, b: 2] 
def b = [b:1,c:3] 

def c = additionJoin(a, b) 

println c 
13

Esto debería funcionar para cualquier número de mapas:

def maps = [[a: 1, b: 2], [b:1, c:3]] 

def result = [:].withDefault{0} 
maps.collectMany{ it.entrySet() }.each{ result[it.key] += it.value } 

assert result == [a: 1, b: 3, c: 3] 

La expresión maps.collectMany{ it.entrySet() } devuelve una lista de entradas de mapa, como [a=1, b=2, b=1, c=3], y luego cada uno de ellos se agrega al resultado.

Otra opción, si desea mantener toda la transformación en una expresión y hacerla "más funcional", es agrupar primero las entradas por clave y luego sumar los valores, pero creo que es menos legible:

def result = maps.collectMany{ it.entrySet() } 
    .groupBy{ it.key } 
    .collectEntries{[it.key, it.value.sum{ it.value }]} 

la parte groupBy devuelve un mapa de la forma [a:[a=1], b:[b=2, b=1], c:[c=3]] y luego los collectEntries transformaciones que el mapa en otra que tiene el mismo kays pero tiene la suma de las listas en los valores en su lugar.

+0

+1 buen uso de 'collectMany' (me inspiró para escribir un método vararg) –

+0

¡Genial! Me gusta cómo se ve el método "combinar". Esto es totalmente fuera de tema e irrelevante, pero, ¿no es extraño que al escribir llamadas encadenadas como 'foo.bar {...} .baz {...} 'debe haber un espacio entre el nombre del método y la llave de apertura del cierre, pero no entre el corsé de cierre y el siguiente operador de punto? Pensé que se veía raro cuando escribí mi respuesta, así que eliminé el primer espacio, pero tampoco se ve muy bien ... – epidemian

+0

Sí, es porque los paréntesis son opcionales si el último parámetro de un método es un cierre ... Es difícil conseguir que se vea bien a veces ;-) –

3

Una buena manera es usar el operador de difusión:

def m1 = [ a:1, b:2 ] 
def m2 = [ b:1, c:3 ] 
def m3 = [ *:m1, *:m2 ] 

println "m1 = $m1" 
println "m2 = $m2" 
println "m3 = $m3" 

* Crédito: http://mrhaki.blogspot.ch/2009/09/groovy-goodness-spread-operator.html

El código anterior no funciona en groovysh pero está muy bien en la consola maravilloso. (Para la versión 1.8)

+2

Lo siento, no me di cuenta de que quería aplicar la suma en los valores de los mapas. – Enio

4

El siguiente ejemplo muestra cómo agregar dos mapas, a un tercer mapa m3:

Map m1 = [ a:1, b:2 ]; 
Map m2 = [ b:1, c:3 ]; 
Map m3 = [:]; 
m3 << m1 
m3 << m2 
+0

Parece respondida sin leer la pregunta. Quería agregar valor de ambos mapas si la clave es mapeo. No responde la pregunta – Rao

+0

¡No puedes culparlo cuando el título es tan confuso! –

0
def merge(map1, map2) { 
    def add = { map, entry -> map << entry } 
    map2.inject(map1.inject([:], add), add) 
} 
+0

¿Tal vez algo más de información? – Loko

+0

Esto no responde la pregunta. Perder la clave 'a' y no agregar valores de ambos mapas para la clave' b' – Rao

Cuestiones relacionadas