一、概述
在这篇快速文章中,我们将了解如何在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()
的最后一个参数是一个映射函数。使用这个,我们可以自定义应该添加哪个键,以防有重复。在上面的示例中,如果源映射包含重复值,我们将保留第一个值作为键。但是,如果值重复,我们只能保留一个键。
0 评论