java - java stream groupingBy + aggregate
问题描述
public class Member {
private String name;
private String team;
private List<String> tasks;
...
}
input list like:
member1, team1, [task1]
member2, team1, [task2]
member2, team1, [taks3]
member3, team2, [task4]
member3, team2, [task5, task6]
Try to group by team and aggregate the tasks for each member together, how to write the stream? The expected result is Map<String, List<Member>>
like:
team1: [
member1: [task1]
member2: [task2, task3]
]
team2: [
member3: [task4, task5, task6]
]
grouping by team is easy. The challenge is how to aggregate the tasks for each different member and still maintain the result as `Map>
UPDATE: This is the best I can do, but it's 2 steps. Can anyone merge these to one?
public class Test {
public static void main(String[] args) {
Member m1 = new Member("member1", "team1", task("task1"));
Member m2 = new Member("member2", "team1", task("task2"));
Member m3 = new Member("member2", "team1", task("task3"));
Member m4 = new Member("member3", "team2", task("task4"));
Member m5 = new Member("member3", "team2", task("task5"));
List<Member> list = Arrays.asList(m1, m2, m3, m4, m5);
long start = System.currentTimeMillis();
Map<String, Map<String, Optional<Member>>> result = list.stream()
.collect(Collectors.groupingBy(Member::getTeam,
Collectors.groupingBy(Member::getName, Collectors.reducing(
(member1, member2) -> {
member1.getTasks().addAll(member2.getTasks());
return member1;
}
))));
Map<String, List<Member>> result2 = result.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey(),
entry -> entry.getValue().values().stream()
.map(e -> e.get()).collect(Collectors.toList())));
result2.entrySet().stream().forEach(System.out::println);
long end = System.currentTimeMillis();
System.out.println("Total:" + (end - start) + "ms");
}
private static List<String> task(String... tasks) {
List<String> list = new ArrayList<>();
Collections.addAll(list, tasks);
return list;
}
}
解决方案
以下收集器组合应该做到这一点。
我确信这是一个很好的例子,说明了技术上的可能性,但在可读性方面并不是一个好主意。
List<Member> list = ...
Map<String, Map<String, List<String>>> map = list.stream()
.collect(Collectors.groupingBy(Member::getTeam,
Collectors.groupingBy(Member::getName,
Collectors.mapping(Member::getTasks,
Collectors.collectingAndThen(Collectors.toList(),
(doubleList) -> doubleList.stream()
.flatMap(lst -> lst.stream())
.collect(Collectors.toList()))))));
当使用以下输入(添加的构造函数)进行测试时:
List<Member> list = Arrays.asList(
new Member("name1", "team1", Arrays.asList("task1", "task11")),
new Member("name1", "team1", Arrays.asList("task2", "task22")),
new Member("name1", "team2", Arrays.asList("task1", "task11")));
生成的地图包含:
{team1={name1=[task1, task11, task2, task22]}, team2={name1=[task1, task11]}}
推荐阅读
- wordpress - 为我的插件制作更新通知功能
- .net - 从网站解析 JSON 随机错误 500
- video-editing - Adobe Premiere 将 bin 中的剪辑导出为单个 MP4 剪辑
- python - 具有 2 个连续递归语句的函数输出
- javascript - 如何使用 jQuery 选择父级的 ID?
- c++ - 在 QtGUI 中还有谁调用paint 方法?
- javascript - 如何检索返回的 JS 函数值并将其传递给 Flask
- r - 使用管道找到平方和
- wordpress - 删除后高级自定义字段留在页面上
- oracle-apex - 在 Oracle APEX 页面上使用图像