章
目
录
这个Java教程将教我们如何使用不同的技术来反转给定的Map的key和value。我们将学习如何反转具有唯一值的Map,并在存在重复值时创建Multimap。
1.什么是反转的Map?
一个反转的Map <V, K> 是原始Map<K, V>的一个实例。原始Map的值成为结果Map的键,而原始Map的键成为值。
Map<String, String> map = Map.of("key1", "value1", "key2", "value2");
System.out.println(map); //{key1=value1, key2=value2}
//反转后
{value1=key1, value2=key2}
2.反转具有唯一值的Map
以下方法应该用于反转包含唯一值的Map,因为我们没有使用任何机制来解决重复的键/值。
2.1. 使用for循环
反转Map的最简单方式是使用循环。我们遍历Map的条目并将它们添加到一个新的Map中。在添加条目时,我们互换键和值。
Map<Integer, String> invertedMap = new HashMap<>();
for (Map.Entry<String, Integer> entry : originalMap.entrySet()) {
invertedMap.put(entry.getValue(), entry.getKey());
}
2.2. 使用Collectors.toMap()
Stream API提供了Collectors.toMap()来方便地将Stream元素收集到Map中。我们需要遍历Stream元素并按相反的顺序收集条目。
Map<Integer, String> inverseMap = originalMap.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
3.反转具有重复值的Map
假设Map中有一些具有重复值的条目。现在,在反转Map时,我们必须决定如何处理这些值,因为反转后的Map不允许重复的键。
通常,在这些情况下创建一个MultiMap是正确的解决方案。MultiMap类似于一个Map,不同之处在于可以有相同的键对应多个元素。
3.1. 使用for循环
在下面的示例中,使用一个List来存储一个键的多个值,从而得到一个Multimap。
Map<Integer, String> mapWithDuplicateValues = new HashMap<Integer, String>();
mapWithDuplicateValues.put(1, "Value1");
mapWithDuplicateValues.put(2, "Value2");
mapWithDuplicateValues.put(3, "Value2");
HashMap<String, List<Integer>> inverseMap = new HashMap<String, List<Integer>>();
for (Map.Entry<Integer, String> entry : mapWithDuplicateValues.entrySet()) {
if (inverseMap.containsKey(entry.getValue())) {
inverseMap.get(entry.getValue()).add(entry.getKey());
} else {
List<Integer> list = new ArrayList<Integer>();
list.add(entry.getKey());
inverseMap.put(entry.getValue(), list);
}
}
System.out.println(inverseMap); //{Value1=[1], Value2=[2, 3]}
3.2. 使用Collectors.groupBy()
在下面的示例中,Collectors.mapping()函数通过传递给收集器的方式,对重复值执行归约操作,将重复值收集到一个List中。
HashMap<String, List<Integer>> inverseMap = originalMap.entrySet()
.stream()
.collect(Collectors.groupingBy(Entry::getValue,
Collectors.mapping(Entry::getKey, Collectors.toList())));
4.使用Guava库
Guava是由Google创建的开源Java库。它提供了许多有用的集合和接口。我们将使用以下Map来反转给定的Map。
4.1. 使用Multimap
Multimap是一个直接的实现,内部管理重复的值。
Multimap<Integer, String> multimap = ImmutableMultimap.of(1, "Key1", 1, "Key2", 2, "Key3");
System.out.println(multimap); //{1=[Key1, Key2], 2=[Key3]}
4.2. 使用BiMap
BiMap是一个双向Map,维护了Map的反向视图,即键和值颠倒的条目。此Map还确保不会在Map中存储重复的值或键。
BiMap<Integer, String> biMap = ImmutableBiMap.of(1, "Key1", 2, "Key2", 3, "Key3");
BiMap<String, Integer> inverseBiMap = biMap.inverse();
System.out.println(inverseBiMap); //{Key1=1, Key2=2, Key3=3}
还有一个名为HashBiMap的类,它由两个哈希表支持,一个用于键到值的映射,另一个用于值到键的映射。这个实现允许空键和值。
BiMap<Integer,String> originalMap = HashBiMap.create();
//add key-value pairs
BiMap<String, Integer> inversedMap = biMap.inverse();
5.使用Apache Commons-Collections
Apache Commons Collections库提供了各种实现和工具,以便轻松处理集合。我们将使用BidiMap和inverseBidiMap()方法来反转Map,方法与Guava类似。
5.1. 使用BidiMap
BidiMap接口允许在键和值之间进行双向查找。以下是该接口的不同实现:
- DualHashBidiMap:它使用两个HashMap实例,以提供使用键或值快速查找条目。
- DualLinkedHashBidiMap:它使用两个LinkedHashMap实例,以牺牲存储两组链表和映射条目的代价来进行快速查找。
- TreeBidiMap:这个Map基于红黑树实现,保证键-值将根据键和值的自然顺序以升序方式存储。
- DualTreeBidiMap:它使用两个TreeMap实例,使其比TreeBidiMap更昂贵,因为它将每个对象存储两次。我们可以使用inverseBidiMap()方法获得原始Map的反向视图。请注意,当找到重复值时,后面的键将覆盖前面的键。
BidiMap bidiMap = new DualHashBidiMap();
bidiMap.put(1, "Value1");
bidiMap.put(2, "Value2");
System.out.println(bidiMap.inverseBidiMap()); //{Value1=1, Value2=2}
5.2. 使用MapUtils.invertMap()
invertMap()方法返回一个新的HashMap,其中键和值被交换。请注意,如果原始Map对多个键有重复的值,返回的Map将包含其中一个键,但应该映射的确切键将未定义。
Map<Integer, String> hashMap = new HashMap<Integer, String>();
hashMap.put(1,"Value1");
hashMap.put(2,"Value2");
hashMap.put(3,"Value2");
Map<String,Integer> inversedMap1 = MapUtils.invertMap(hashMap);
System.out.println(inversedMap1); //{Value1=1, Value2=3}
6.结论
在这个Java教程中,我们学习了如何使用不同的技术反转给定的Map,从for循环到Guava和Apache Commons的方法。我们还学习了如何反转具有重复值的Map。反转给定的Map的有效方式是使用外部库,如Guava或Apache Commons,而不是遍历条目。