將所有鍵和值從一個哈希映射複製到另一個哈希圖中而不替換現有鍵和值
一、簡介
在本教程中,我們將了解如何將一個HashMap
複製到另一個 HashMap 而無需替換目標HashMap.
Java中的HashMap
是Map
接口的哈希表實現,是一種支持存儲鍵值對的數據結構。
2.問題陳述
考慮我們有兩個HashMap
s ,
sourceMap
和targetMap,
包含國家和他們的首都作為鍵和值.
我們想將sourceMap
的內容複製到targetMap
中,這樣我們只有一張包含所有國家及其首都的地圖。複製應遵守以下規則:
- 我們應該保留
targetMap
的原始內容 - 如果鍵發生衝突,例如兩個地圖中都存在的城市,我們應該保留
targetMap
的條目
讓我們接受以下輸入:
Map<String, String> sourceMap = new HashMap<>();
sourceMap.put("India", "Delhi");
sourceMap.put("United States", "Washington DC");
sourceMap.put("United Kingdom", "London DC");
Map<String, String> targetMap = new HashMap<>();
targetMap.put("Zimbabwe", "Harare");
targetMap.put("Norway", "Oslo");
targetMap.put("United Kingdom", "London");
修改後的targetMap
保留其值並添加sourceMap
的所有值:
"India", "Delhi"
"United States", "Washington DC"
"United Kingdom", "London"
"Zimbabwe", "Harare"
"Norway", "Oslo"
3. 遍歷HashMaps
解決我們問題的一種簡單方法是遍歷sourceMap
的每個條目(鍵值對)並將其與targetMap.
當我們找到只存在於sourceMap
中的條目時,我們將它添加到targetMap.
生成的targetMap
包含其自身和sourceMap.
我們可以遍歷sourceMap
的entrySets()
並檢查targetMap
中是否存在鍵,而不是遍歷兩個映射的entrySet()
:
Map<String, String> copyByIteration(Map<String, String> sourceMap, Map<String, String> targetMap) {
for (Map.Entry<String, String> entry : sourceMap.entrySet()) {
if (!targetMap.containsKey(entry.getKey())) {
targetMap.put(entry.getKey(), entry.getValue());
}
}
return targetMap;
}
4. 使用Map
的putIfAbsent()
我們可以重構上面的代碼,使用 Java 8 中新增的putIfAbsent()
方法。該方法顧名思義,只有當指定條目中的鍵不存在時,才會將sourceMap
的一個條目複製到targetMap
中:
Map<String, String> copyUsingPutIfAbsent(Map<String, String> sourceMap, Map<String, String> targetMap) {
for (Map.Entry<String, String> entry : sourceMap.entrySet()) {
targetMap.putIfAbsent(entry.getKey(), entry.getValue());
}
return targetMap;
}
使用循環的另一種方法是使用 Java 8 中添加的forEach
結構。我們提供了一個操作,在我們的例子中是在targetMap
輸入上調用putIfAbsent()
方法,它對給定HashMap
的每個條目執行直到所有元素都已處理或引發異常:
Map<String, String> copyUsingPutIfAbsentForEach(Map<String, String> sourceMap, Map<String, String> targetMap) {
sourceMap.forEach(targetMap::putIfAbsent);
return targetMap;
}
5. 使用Map
的putAll()
Map
接口提供了一個方法putAll()
,我們可以使用它來實現我們想要的結果。該方法將輸入映射的所有鍵和值複製到當前映射中。在這裡我們應該注意,如果源哈希映射和目標哈希映射之間發生鍵衝突,則來自源的條目將替換targetMap
的條目。
我們可以通過從sourceMap
中顯式刪除公共鍵來解決這個問題:
Map<String, String> copyUsingPutAll(Map<String, String> sourceMap, Map<String, String> targetMap) {
sourceMap.keySet().removeAll(targetMap.keySet());
targetMap.putAll(sourceMap);
return targetMap;
}
6. 在Maps
上使用merge()
Java 8 在Maps
接口中引入了merge()
方法。它需要一個鍵、一個值和一個作為方法參數的重新映射。
假設我們在輸入中指定的鍵尚未與當前映射中的值關聯(或與null
關聯)。在這種情況下,該方法將它與提供的非null
值相關聯。
如果鍵在兩個映射中都存在,則關聯的值將替換為給定重新映射函數的結果。如果重新映射函數的結果為null
,它會刪除鍵值對。
我們可以使用merge()
方法將條目從sourceMap
複製到targetMap
:
Map<String, String> copyUsingMapMerge(Map<String, String> sourceMap, Map<String, String> targetMap) {
sourceMap.forEach((key, value) -> targetMap.merge(key, value, (oldVal, newVal) -> oldVal));
return targetMap;
}
我們的重映射函數確保它在發生碰撞時保留targetMap
中的值。
7. 使用 Guava 的Maps.difference()
Guava 庫在其Maps
類中使用difference()
方法。要使用Guava
庫,我們應該在我們的pom.xml
中添加相應的依賴項:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
difference()
方法將兩個映射作為輸入併計算這兩個映射之間的差異。提供的映射的鍵應該遵守equals()
和hashCode()
契約。
為了解決我們的問題,我們首先評估地圖之間的差異。一旦我們知道僅存在於sourceMap
(左側地圖)中的條目,我們將它們放入我們的targetMap
中:
Map<String, String> copyUsingGuavaMapDifference(Map<String, String> sourceMap, Map<String, String> targetMap) {
MapDifference<String, String> differenceMap = Maps.difference(sourceMap, targetMap);
targetMap.putAll(differenceMap.entriesOnlyOnLeft());
return targetMap;
}
八、結論
在本文中,我們研究了將條目從一個HashMap
複製到另一個 HashMap 的不同方法,同時保留目標HashMap.
我們實施了一種基於迭代的方法,並使用不同的 Java 庫函數解決了這個問題。我們還研究瞭如何使用 Guava 庫解決問題。
與往常一樣,所有代碼示例都可以在 GitHub 上找到.