2010-11-28 104 views
171

我有两个HashMap对象定义,像这样:如何组合两个包含相同类型的HashMap对象?

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

我也有第三HashMap对象:

HashMap<String, Integer> map3; 

如何合并map1map2连成map3

+8

你还没有说明你想要发生什么,如果一个密钥存在这两个地图。 – 2013-12-16 01:05:34

+5

Java 8有map1.merge(map2) – 2015-04-08 23:56:06

+4

@SambitTripathy,你有关于该文档的链接吗?我似乎无法找到它。 – JohnK 2016-08-05 20:54:16

回答

234
map3 = new HashMap<>(); 

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

如果您不需要为可变性最终的地图,有Guava'sImmutableMapBuilderputAll method其中,相对于Java's Map interface method,可以链接。使用

例子:

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

当然,这种方法能够更加通用,使用可变参数和循环来putAllMaps从参数等,但我想展示的概念。

此外,ImmutableMapBuilder有一些限制(或者特点?):

  • 它们是空敌对(扔NullPointerException - 如果map中的任何键或值为null)
  • 生成器不要t接受重复密钥(如果添加了重复密钥,则引发IllegalArgumentException)。
74

如果你知道你没有重复键,或者你想在map2值从map1的重复键覆盖值,你可以只写

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

如果您需要在如何更好地控制值合并后,可以使用Map.merge,在Java 8中添加,它使用用户提供的BiFunction合并重复键的值。 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)); 

如果你知道你没有重复键,并希望执行它,你可以使用抛出AssertionError合并功能:

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

服用从这个特定问题退步,Java 8流库提供了toMapgroupingByCollectors。如果你在一个循环中重复合并地图,你可能会重构你的计算以使用流,这既能够澄清你的代码,又能使用并行流和并发采集器来实现简单的并行处理。

8

爪哇8替代单行用于合并两个映射:

defaultMap.forEach((k, v) -> destMap.putIfAbsent(k, v)); 

与方法参考相同:

defaultMap.forEach(destMap::putIfAbsent); 

或者idemponent用于与第三地图原始地图溶液:

Map<String, Integer> map3 = new HashMap<String, Integer>(map2); 
map1.forEach(map3::putIfAbsent); 

这里有一种方法可以将两张地图合并为快速不可变的地图,其中Guava小号至少可能的中间复制操作:

ImmutableMap.Builder<String, Integer> builder = ImmutableMap.<String, Integer>builder(); 
builder.putAll(map1); 
map2.forEach((k, v) -> {if (!map1.containsKey(k)) builder.put(k, v);}); 
ImmutableMap<String, Integer> map3 = builder.build(); 

Merge two maps with Java 8参见情况下,当存在于两个映射值需要与映射函数进行组合。

20

一衬垫使用Java 8个流API:

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

在这种方法的好处是通过合并功能的能力,这将处理有相同的密钥值,例如:

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

你可以使用 - 中的addAll方法

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

但总是有这个问题 - 如果你的两个哈希映射有相同的任何关键 - 那么它将覆盖第一个哈希映射的密钥值和第二个哈希映射的密钥值。

用于被更安全侧 - 更改密钥值 - 则可以使用上的按键前缀或后缀 - (不同的前缀/后缀为第一散列图和第二哈希映射不同的前缀/后缀)

7

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

就地:

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; 
} 
相关问题