我有两个HashMap对象,定义如下:

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

我还有第三个HashMap对象:

HashMap<String, Integer> map3;

如何将map1和map2合并为map3?


当前回答

您可以使用- addAll方法

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

但是总会有这样的问题,如果你的两个哈希映射有相同的键,那么它会用第二个哈希映射的键值覆盖第一个哈希映射的键值。

为了安全起见-更改键值-您可以在键上使用前缀或后缀-(第一个哈希映射使用不同的前缀/后缀,第二个哈希映射使用不同的前缀/后缀)

其他回答

如果知道没有重复的键,或者希望map2中的值覆盖map1中的值以获得重复的键,那么可以只写

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

如果需要更多地控制值的组合方式,可以使用Map。merge,在Java 8中添加,它使用用户提供的biffunction来合并重复键的值。merge操作单独的键和值,因此需要使用循环或Map.forEach。这里我们连接重复键的字符串:

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));

如果你知道你没有重复的键,并且想要强制它,你可以使用merge函数抛出AssertionError:

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

从这个特定的问题后退一步,Java 8流库提供了toMap和groupingBy collector。如果在循环中重复合并映射,则可以重新构造计算以使用流,这既可以澄清代码,又可以使用并行流和并发收集器轻松实现并行。

你可以使用HashMap<String, List<Integer>>来合并两个HashMap,避免丢失与相同键配对的元素。

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 + "}"));

输出:

{key1: [1, 4]}
{key2: [2, 5]}
{key3: [3, 6]}
map3 = new HashMap<>();

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

组合两个可能共享公共键的映射的通用解决方案:

就地:

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));
}

返回一个新地图:

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;
}

使用Java 8 Stream API的一行程序:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue))

该方法的好处之一是能够传递一个merge函数,该函数将处理具有相同键的值,例如:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue, Math::max))