我是lambda表达的新手,并试图在我的任务中使用它。
问题:
我有两个类型为m1
的地图m2
和Map<Integer, String>
,必须合并到一个地图中
Map<Integer, List<String>>
,其中两个地图中相同键的值都被收集到一个列表中并放入一个新的地图中。
基于我探索的解决方案:
Map<Integer, List<String>> collated =
Stream.concat(m1.entrySet().stream(), m2.entrySet().stream()).collect(
Collectors.toMap(Entry::getKey,
Entry::getValue, (a, b) -> {
List<String> merged = new ArrayList<String>(a);
merged.addAll(b);
return merged;
}));
但是,此解决方案期望源List
为Map<Integer, List<String>>
,因为toMap中的合并函数需要操作数和结果具有相同的类型。
我不想更改源集合。请提供您使用lambda表达式实现此目的的输入。
答案 0 :(得分:21)
这是groupingBy
收藏家的工作:
Stream.of(m1,m2)
.flatMap(m->m.entrySet().stream())
.collect(groupingBy(
Map.Entry::getKey,
mapping(Map.Entry::getValue, toList())
));
答案 1 :(得分:11)
我现在无法测试它,但我认为你需要它来改变从Entry :: getValue到包含该值的List的值的映射:
Map<Integer, List<String>> collated =
Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey,
e -> {
List<String> v = new ArrayList<String>();
v.add(e.getValue());
return v;
},
(a, b) -> {
List<String> merged = new ArrayList<String>(a);
merged.addAll(b);
return merged;
}));
编辑:这个想法是正确的。语法不是。当前语法有效,但有点难看。必须有一个更短的方式来编写它。
您也可以将e -> {..}
替换为e -> new ArrayList<String>(Arrays.asList(new String[]{e.getValue()}))
。
或e -> Stream.of(e.getValue()).collect(Collectors.toList())
编辑:
或者您可以使用groupingBy
:
Map<Integer, List<String>> collated =
Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())));
答案 2 :(得分:3)
Map<Integer, List<String>> map = StreamEx.of(m1, m2)
.flatMapToEntry(Function.identity())
.grouping();
在内部,它与Misha的解决方案相同,只是语法糖。
答案 3 :(得分:3)
这似乎是使用番石榴Multimap
的绝佳机会。
ListMultimap<Integer, String> collated = ArrayListMultimap.create();
collated.putAll(Multimaps.forMap(m1));
collated.putAll(Multimaps.forMap(m2));
如果你真的需要Map<Integer, List<String>>
:
Map<Integer, List<String>> mapCollated = Multimaps.asMap(collated);
答案 4 :(得分:0)
为了清楚起见,您可以使用带有三个参数的 Collectors.toMap
方法。
Map<Integer, String> m1 = Map.of(1, "A", 2, "B");
Map<Integer, String> m2 = Map.of(1, "C", 2, "D");
// two maps into one
Map<Integer, List<String>> m3 = Stream
.of(m1.entrySet(), m2.entrySet())
.flatMap(Collection::stream)
.collect(Collectors.toMap(
// key - Integer
e -> e.getKey(),
// value - List<String>
e -> List.of(e.getValue()),
// mergeFunction - two lists into one
(list1, list2) -> {
List<String> list = new ArrayList<>();
list.addAll(list1);
list.addAll(list2);
return list;
}));
// output
System.out.println(m3); // {1=[A, C], 2=[B, D]}