java hashset - ¿Cómo puedo combinar dos objetos HashMap que contengan los mismos tipos?




como funciona (10)

Solución genérica para combinar dos mapas que posiblemente puedan compartir claves comunes:

En su lugar:

public static <K, V> void mergeInPlace(Map<K, V> map1, Map<K, V> map2,
        BinaryOperator<V> combiner) {
    map2.forEach((k, v) -> map1.merge(k, v, combiner::apply));
}

Devolviendo un nuevo mapa:

public static <K, V> Map<K, V> merge(Map<K, V> map1, Map<K, V> map2,
        BinaryOperator<V> combiner) {
    Map<K, V> map3 = new HashMap<>(map1);
    map2.forEach((k, v) -> map3.merge(k, v, combiner::apply));
    return map3;
}

Tengo dos objetos HashMap definidos así:

HashMap<String, Integer> map1 = new HashMap<String, Integer>();
HashMap<String, Integer> map2 = new HashMap<String, Integer>();

También tengo un tercer objeto HashMap :

HashMap<String, Integer> map3;

¿Cómo puedo fusionar map1 y map2 juntos en map3 ?


Si sabe que no tiene claves duplicadas, o si desea que los valores en map2 sobrescriban los valores de map1 para las claves duplicadas, simplemente puede escribir

map3 = new HashMap<>(map1);
map3.putAll(map2);

Si necesita más control sobre cómo se combinan los valores, puede usar Map.merge , agregado en Java 8, que usa un BiFunction proporcionado por el BiFunction para combinar valores para claves duplicadas. merge funciona con claves y valores individuales, por lo que deberá usar un bucle o Map.forEach . Aquí concatenamos cadenas para claves duplicadas:

map3 = new HashMap<>(map1);
for (Map.Entry<String, String> e : map2.entrySet())
    map3.merge(e.getKey(), e.getValue(), String::concat);
//or instead of the above loop
map2.forEach((k, v) -> map3.merge(k, v, String::concat));

Si sabe que no tiene claves duplicadas y desea aplicarlas, puede usar una función de combinación que arroja un AssertionError :

map2.forEach((k, v) ->
    map3.merge(k, v, (v1, v2) ->
        {throw new AssertionError("duplicate values for key: "+k);}));

Dejando un paso atrás de esta pregunta específica, la biblioteca de secuencias de Java 8 proporciona toMap y groupingBy Collectors . Si está fusionando repetidamente los mapas en un bucle, es posible que pueda reestructurar su computación para usar flujos, lo que puede aclarar su código y habilitar el paralelismo fácil usando un flujo paralelo y un colector concurrente.


Si no necesita la mutabilidad para su mapa final, está el Guava's con su método Builder y putAll que, a diferencia del método de la interfaz del Map de Java , puede encadenarse.

Ejemplo de uso:

Map<String, Integer> mergeMyTwoMaps(Map<String, Integer> map1, Map<String, Integer> map2) {
  return ImmutableMap.<String, Integer>builder()
      .putAll(map1)
      .putAll(map2)
      .build();
}

Por supuesto, este método puede ser más genérico, use varargs y loop para putAll Maps de argumentos, etc. pero quería mostrar un concepto.

Además, ImmutableMap y su Builder tienen pocas limitaciones (¿o quizás características?):

  • son nulos hostiles (lanza NullPointerException - si alguna clave o valor en el mapa es nulo)
  • El IllegalArgumentException no acepta claves duplicadas (lanza la IllegalArgumentException si se agregaron claves duplicadas).

map3 = new HashMap<>();

map3.putAll(map1);
map3.putAll(map2);

puede usar HashMap<String, List<Integer>> para combinar ambos hashmaps y evitar perder elementos emparejados con la misma clave.

HashMap<String, Integer> map1 = new HashMap<>();
HashMap<String, Integer> map2 = new HashMap<>();
map1.put("key1", 1);
map1.put("key2", 2);
map1.put("key3", 3);
map2.put("key1", 4);
map2.put("key2", 5);
map2.put("key3", 6);
HashMap<String, List<Integer>> map3 = new HashMap<>();
map1.forEach((str, num) -> map3.put(str, new ArrayList<>(Arrays.asList(num))));
//checking for each key if its already in the map, and if so, you just add the integer to the list paired with this key
for (Map.Entry<String, Integer> entry : map2.entrySet()) {
    Integer value = entry.getValue();
    String key = entry.getKey();
    if (map3.containsKey(key)) {
        map3.get(key).add(value);
    } else {
        map3.put(key, new ArrayList<>(Arrays.asList(value)));
    }
}
map3.forEach((str, list) -> System.out.println("{" + str + ": " + list + "}"));

salida:

{key1: [1, 4]}
{key2: [2, 5]}
{key3: [3, 6]}

Podría usar Collection.addAll() para otros tipos, por ejemplo, List , Set , etc. Para Map , puede usar putAll .


Un pequeño fragmento de código que utilizo muy a menudo para crear mapas a partir de otros mapas:

static public <K, V> Map<K, V> merge(Map<K, V>... args) {
    final Map<K, V> buffer = new HashMap<>();

    for (Map m : args) {
        buffer.putAll(m);
    }

    return buffer;
}

puedes usar - método addAll

http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html

Pero siempre existe el problema de que, si sus dos mapas hash tienen la misma clave, entonces reemplazará el valor de la clave del primer mapa hash con el valor de la clave del segundo mapa hash.

Para estar en el lado más seguro, cambie los valores clave, puede usar prefijo o sufijo en las teclas (prefijo / sufijo diferente para el primer mapa hash y prefijo / sufijo diferente para el segundo mapa hash)



¿Qué hay de replaceAll("\\s", "") . Consulte here .





java hashmap