Nic*_*lis 4 java java-8 java-stream
我有以下对象:
class Event {
private LocalDateTime when;
private String what;
public Event(LocalDateTime when, String what) {
super();
this.when = when;
this.what = what;
}
public LocalDateTime getWhen() {
return when;
}
public void setWhen(LocalDateTime when) {
this.when = when;
}
public String getWhat() {
return what;
}
public void setWhat(String what) {
this.what = what;
}
Run Code Online (Sandbox Code Playgroud)
}
我需要按年/月(yyyy-mm)和事件类型聚合,然后计数。例如下面的列表
List<Event> events = Arrays.asList(
new Event(LocalDateTime.parse("2017-03-03T09:01:16.111"), "EVENT1"),
new Event(LocalDateTime.parse("2017-03-03T09:02:11.222"), "EVENT1"),
new Event(LocalDateTime.parse("2017-04-03T09:04:11.333"), "EVENT1"),
new Event(LocalDateTime.parse("2017-04-03T09:04:11.333"), "EVENT2"),
new Event(LocalDateTime.parse("2017-04-03T09:06:16.444"), "EVENT2"),
new Event(LocalDateTime.parse("2017-05-03T09:01:26.555"), "EVENT3")
);
Run Code Online (Sandbox Code Playgroud)
应该产生以下结果:
Year/Month Type Count
2017-03 EVENT1 2
2017-04 EVENT1 1
2017-04 EVENT2 2
2017-04 EVENT3 1
Run Code Online (Sandbox Code Playgroud)
知道我是否(如果可以,如何)使用 Streams API 实现这一目标?
如果您不想按照 assylias 的建议创建一个新的密钥类,您可以执行双重操作 groupingBy
Map<YearMonth,Map<String,Long>> map =
events.stream()
.collect(Collectors.groupingBy(e -> YearMonth.from(e.getWhen()),
Collectors.groupingBy(x -> x.getWhat(), Collectors.counting()))
);
Run Code Online (Sandbox Code Playgroud)
... 后跟嵌套打印
map.forEach((k,v)-> v.forEach((a,b)-> System.out.println(k + " " + a + " " + b)));
Run Code Online (Sandbox Code Playgroud)
这打印
2017-05 EVENT3 1
2017-04 EVENT2 2
2017-04 EVENT1 1
2017-03 EVENT1 2
Run Code Online (Sandbox Code Playgroud)
编辑:我注意到日期的顺序与 OP 的预期解决方案相反。使用 3 参数版本groupingBy可以指定排序的映射实现
Map<YearMonth,Map<String,Long>> map =
events.stream()
.collect(Collectors.groupingBy(e -> YearMonth.from(e.getWhen()), TreeMap::new,
Collectors.groupingBy(x -> x.getWhat(), Collectors.counting()))
);
Run Code Online (Sandbox Code Playgroud)
同样的map.forEach(...)现在打印
2017-03 EVENT1 2
2017-04 EVENT2 2
2017-04 EVENT1 1
2017-05 EVENT3 1
Run Code Online (Sandbox Code Playgroud)
您可以创建一个包含年/月和事件类型的“键”类:
class Group {
private YearMonth ym;
private String type;
public Group(Event e) {
this.ym = YearMonth.from(e.getWhen());
this.type = e.getWhat();
}
//equals, hashCode, toString etc.
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用该键对事件进行分组:
Map<Group, Long> result = events.stream()
.collect(Collectors.groupingBy(Group::new, Collectors.counting()));
result.forEach((k, v) -> System.out.println(k + "\t" + v));
Run Code Online (Sandbox Code Playgroud)
其输出:
2017-04 EVENT1 1
2017-03 EVENT1 2
2017-04 EVENT2 2
2017-05 EVENT3 1
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11223 次 |
| 最近记录: |