我正在尝试实现该功能:
private static <T, K> Map<T, List<K> > invertedMap(Map<K, List<T> > m)
例如,如果我有Map<String, List<Integer> >
,
我想创建另一个Map<Integer, List<String> >
。
我写了一些代码:
private static <T, K> Map<T, List<K>> invertedMap(Map<K, T> m) {
return m.keySet().stream()
.collect(Collectors.groupingBy(k -> m.get(k)));
}
但是如您所见,这仅在参数中的映射不包含列表作为值的情况下有效。
答案 0 :(得分:8)
我不会为此使用流(如果您想要基于流的解决方案,请选中nullpointer's answer):
private static <T, K> Map<T, List<K>> invertedMap(Map<K, List<T>> map) {
Map<T, List<K>> result = new LinkedHashMap<>(); // Preserves insertion order
map.forEach((k, l) ->
l.forEach(t -> result.computeIfAbsent(t, d -> new ArrayList<>()).add(k)));
return result;
}
上面的代码迭代输入映射map
,并为其t
值List
中的每个元素的每个元素l
使用Map.computeIfAbsent
创建结果。
Map.computeIfAbsent
返回值(如果有给定键的条目),或者创建该条目并返回其第二个参数d -> new ArrayList<>()
指定的值(此处d
代表虚拟参数我们不需要创建新的空白列表)。然后,将密钥k
添加到Map.computeIfAbsent
返回的列表中。
答案 1 :(得分:6)
这是 stream 的一种处理方式(尽管我的本能是遵循answer):
private static <T, K> Map<T, List<K>> invertedMapOfList(Map<K, List<T>> m) {
return m.entrySet()
.stream()
.flatMap(e -> e.getValue()
.stream()
.map(v -> new AbstractMap.SimpleEntry<>(e.getKey(), v)))
.collect(Collectors.groupingBy(Map.Entry::getValue,
Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
}
答案 2 :(得分:2)
希望这可以解决您的问题。
private static <T, K> Map<T, List<K>> invertedMap(Map<K, List<T>> m) {
Map<T, List<K>> result = new HashMap<T, List<K>>();
for (K key : m.keySet()) {
for (T value : m.get(key)) {
List<K> kList = null;
if ((kList = result.get(value)) == null) {
kList = new ArrayList<K>();
}
kList.add(key);
result.put(value, kList);
}
}
return result;
}
答案 3 :(得分:1)
此解决方案与answer by Federico Peralta Schaffner中建议的解决方案类似,不同之处在于它使用for
循环而不是forEach
。我主要将其发布为具有MCVE和输入/输出的简短示例,还可以作为基于流的解决方案的平衡点。现在人们可以争论可读性和可维护性。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class InvertMapWithLists
{
public static void main(String[] args)
{
Map<String, List<Integer>> map =
new LinkedHashMap<String, List<Integer>>();
map.put("A", Arrays.asList(0,1,2));
map.put("B", Arrays.asList(2,3,4));
map.put("C", Arrays.asList(4,5,6));
System.out.println("Original:");
map.entrySet().forEach(System.out::println);
Map<Integer, List<String>> inverted = invert(map);
System.out.println("Inverted");
inverted.entrySet().forEach(System.out::println);
}
private static <T, K> Map<T, List<K>> invert(
Map<K, ? extends Collection<? extends T>> map)
{
Map<T, List<K>> result = new LinkedHashMap<T, List<K>>();
for (Entry<K, ? extends Collection<? extends T>> entry : map.entrySet())
{
for (T element : entry.getValue())
{
List<K> list = result.computeIfAbsent(
element, v -> new ArrayList<K>());
list.add(entry.getKey());
}
}
return result;
}
}
输出为
Original:
A=[0, 1, 2]
B=[2, 3, 4]
C=[4, 5, 6]
Inverted
0=[A]
1=[A]
2=[A, B]
3=[B]
4=[B, C]
5=[C]
6=[C]