如何在Java 中反轉Map
- java
一、概述
在這篇快速文章中,我們將了解如何在 Java 中反轉Map
。這個想法是為Map<K, V>
類型的給定地圖創建Map<V, K>
的新實例。此外,我們還將了解如何處理源映射中存在重複值的情況。
請參閱我們的另一篇文章以了解有關HashMap類本身的更多信息。
2. 定義問題
假設我們有一個包含幾個Key-Value
對的Map
:
Map<String, Integer> map = new HashMap<>();
map.put("first", 1);
map.put("second", 2);
原始Map
將存儲以下項目:
{first=1, second=2}
相反,我們希望將鍵轉換為值,反之亦然,轉換為新的Map
對象。結果將是:
{1=first, 2=second}
3. 使用傳統for
循環
首先,讓我們看看如何使用for
循環反轉Map
:
public static <V, K> Map<V, K> invertMapUsingForLoop(Map<K, V> map) {
Map<V, K> inversedMap = new HashMap<V, K>();
for (Entry<K, V> entry : map.entrySet()) {
inversedMap.put(entry.getValue(), entry.getKey());
}
return inversedMap;
}
在這裡,我們正在遍歷Map
對象的entrySet()
。之後,我們將原來的Value
作為新的Key
,將原來的Key
作為新的Value
添加到inversedMap
對像.
換句話說,我們通過用值替換鍵和用鍵替換值來複製映射的內容。此外,這適用於 8 之前的 Java 版本,但我們應該注意,這種方法僅在源映射的值是唯一的情況下才有效。
4. 使用Stream
API 反轉Map
Java 8 提供了來自Stream
API 的便捷方法,以更實用的風格反轉Map
。讓我們來看看其中的幾個。
4.1. Collectors.groupingBy()
有時,即使源映射包含重複值,我們也可能需要所有鍵。或者, Collectors.groupingBy()
為處理重複值提供了更好的控制。
例如,假設我們有以下Key
Value
:
{first=1, second=2, two=2}
這裡,值“2”針對不同的鍵重複兩次。在這些情況下,我們可以使用groupingBy()
方法在Value
對像上實現級聯的“分組依據”操作:
private static <V, K> Map<V, List<K>> invertMapUsingGroupingBy(Map<K, V> map) {
Map<V, List<K>> inversedMap = map.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
return inversedMap;
}
稍微解釋一下, Collectors.mapping()
函數使用指定的收集器對與給定鍵關聯的值執行歸約操作。 groupingBy()
收集器將重複值收集到List
中,從而產生MultiMap
。現在的輸出將是:
{1=[first], 2=[two, second]}
4.2 **Collectors.toMap()**
如果源映射中沒有任何重複值,我們可以使用Collectors.toMap()
:
public static <V, K> Map<V, K> invertMapUsingStreams(Map<K, V> map) {
Map<V, K> inversedMap = map.entrySet()
.stream()
.collect(Collectors.toMap(Entry::getValue, Entry::getKey));
return inversedMap;
}
首先, entrySet()
被轉換為對象流。隨後,我們使用Collectors.toMap()
將Key
和Value
收集到inversedMap
對像.
讓我們考慮源映射包含重複值。在這種情況下,我們可以使用映射函數將自定義規則應用於輸入元素:
public static <K, V> Map<V, K> invertMapUsingMapper(Map<K, V> sourceMap) {
return sourceMap.entrySet()
.stream().collect(
Collectors.toMap(Entry::getValue, Entry::getKey, (oldValue, newValue) -> oldValue)
);
}
在這個方法中, Collectors.toMap()
的最後一個參數是一個映射函數。使用這個,我們可以自定義應該添加哪個鍵,以防有重複。在上面的示例中,如果源映射包含重複值,我們將保留第一個值作為鍵。但是,如果值重複,我們只能保留一個鍵。