这是我的列表 fooList
class Foo {
private String name;
private int code;
private int account;
private int time;
private String others;
... constructor, getters & setters
}
例如(账户的所有值已设置为1)
new Foo(First, 200, 1, 400, other1),
new Foo(First, 200, 1, 300, other1),
new Foo(First, 201, 1, 10, other1),
new Foo(Second, 400, 1, 20, other2),
new Foo(Second, 400, 1, 40, other2),
new Foo(Third, 100, 1, 200, other3),
new Foo(Third, 101, 1, 900, other3)
我想通过对“名称”和“代码”进行分组、计算数量并对“时间”求和来转换这些值,例如
new Foo(First, 200, 2, 700, other1),
new Foo(First, 201, 1, 10, other1),
new Foo(Second, 400, 2, 60, other2),
new Foo(Third, 100, 1, 200, other3),
new Foo(Third, 101, 1, 900, other3)
我知道我应该使用这样的流:
Map<String, List<Foo>> map = fooList.stream().collect(groupingBy(Foo::getName()));
但是我如何按代码将它们分组然后进行会计和求和工作?
另外,如果我想计算平均时间怎么办?例如
new Foo(First, 200, 2, 350, other1),
new Foo(First, 201, 1, 10, other1),
new Foo(Second, 400, 2, 30, other2),
new Foo(Third, 100, 1, 200, other3),
new Foo(Third, 101, 1, 900, other3)
我可以同时使用 summingInt(Foo::getAccount)
和 averagingInt(Foo::getTime)
吗?
最佳答案
解决方法可能是使用键作为 List
处理分组
,并在映射回对象类型时进行转换。
List<Foo> result = fooList.stream()
.collect(Collectors.groupingBy(foo ->
Arrays.asList(foo.getName(), foo.getCode(), foo.getAccount()),
Collectors.summingInt(Foo::getTime)))
.entrySet().stream()
.map(entry -> new Foo((String) entry.getKey().get(0),
(Integer) entry.getKey().get(1),
entry.getValue(),
(Integer) entry.getKey().get(2)))
.collect(Collectors.toList());
更简洁的方法是公开用于合并功能的 API 并执行 toMap
。
编辑:使用 toMap
进行的简化如下所示
List<Foo> result = new ArrayList<>(fooList.stream()
.collect(Collectors.toMap(foo -> Arrays.asList(foo.getName(), foo.getCode()),
Function.identity(), Foo::aggregateTime))
.values());
其中 aggregateTime
是 Foo
中的静态方法,如下所示:
static Foo aggregateTime(Foo initial, Foo incoming) {
return new Foo(incoming.getName(), incoming.getCode(),
incoming.getAccount(), initial.getTime() + incoming.getTime());
}
关于Java流groupingBy并对多个字段求和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62286182/