2010-11-28 129 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; 
} 
相關問題