Java流分组通过对多个字段求和 [英] Java stream groupingBy and sum multiple fields

查看:166
本文介绍了Java流分组通过对多个字段求和的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的列表fooList

Here is my List fooList

class Foo {
    private String name;
    private int code;
    private int account;
    private int time;
    private String others;

    ... constructor, getters & setters
}

例如(帐户的所有值均已设置为1)

e.g.(all the value of account has been set to 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)

我想通过对名称"进行分组来转换这些值.和代码",说明该数字并求和时间",例如

I want to transform these values by grouping "name" and "code", accounting for the number, and summing the "time", e.g.

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)

我知道我应该使用这样的流:

I know that I should use a stream like this:

Map<String, List<Foo>> map = fooList.stream().collect(groupingBy(Foo::getName()));

但是如何将它们按代码分组,然后进行会计和求和工作呢?

but how can I group them by code then do the accounting and summing job?

此外,如果我想计算平均时间怎么办?例如

Also, what if I want to calculate the average time? e.g.

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)吗?

推荐答案

一种解决方法是处理键为Listgrouping,并在映射回对象类型时进行强制转换.

A workaround could be to deal with grouping with key as List and casting while mapping back to object type.

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());

更干净的方法是公开用于合并功能并执行toMap的API.

Cleaner way would be to expose APIs for merge function and performing a toMap.

修改:使用toMap进行的简化如下所示

Edit: The simplification with toMap would look like the following

List<Foo> result = new ArrayList<>(fooList.stream()
        .collect(Collectors.toMap(foo -> Arrays.asList(foo.getName(), foo.getCode()),
                Function.identity(), Foo::aggregateTime))
        .values());

其中aggregateTimeFoo中的静态方法,例如:

where the aggregateTime is a static method within Foo such as this :

static Foo aggregateTime(Foo initial, Foo incoming) {
    return new Foo(incoming.getName(), incoming.getCode(),
            incoming.getAccount(), initial.getTime() + incoming.getTime());
}

这篇关于Java流分组通过对多个字段求和的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆