使用Stream API对对象求和

时间:2015-02-18 14:35:04

标签: java java-8 java-stream

我目前有以下情况:

我有一个Report对象,可以包含多个Query个对象。 Query个对象具有以下属性:Optional<Filter> comparisonFilterOptional<String> filterChoiceint queryOutput

并非每个查询都有比较过滤器,所以我首先检查一下。然后,我确保我得到了特定过滤器的查询(这不是问题,所以我不会详细讨论)。每个过滤器都有一些选择,其中选择的数量是可变的。

以下是输入的示例(这些Query个对象都具有相同的comparisonFilter):

Query 1 -- Choice: 'First' -- Output: 10
Query 1 -- Choice: 'First' -- Output: 5
Query 1 -- Choice: 'Second' -- Output: 25
Query 1 -- Choice: 'Third' -- Output: 10

现在,我想对每个唯一选择的查询输出求和。我目前有这个代码:

report
.getQueries()
.stream()
.filter(q -> q.getComparisonFilter().isPresent())
.filter(q -> q.getComparisonFilter().get().equals(view.getFilter().get()))
.forEach(query -> {

    //Sum the query outputs per choice

});

我可以通过创建Map<String, Integer>来完成此操作,其中键是选项,值是查询输入。但是我需要再次遍历Map以使用某些值(这里不重要)。

输出应该是这样的:

Choice: 'First' -- Summed Output: 15
Choice: 'Second' -- Summed Output: 25
Choice: 'Third' -- Summed Output: 10

但是我想在流上的forEach中直接使用这个'Summed Output',但是如果这不再可行或不实用,我就可以了。

我想以'Java 8'的方式做到这一点,但我似乎无法弄清楚如何。

所以我的问题是:使用新的Stream API可以缩短时间吗?

注意:如果有人对如何使这个问题更一般(可能是更好的标题和一些概括)有一些想法,请告诉我!

1 个答案:

答案 0 :(得分:6)

如果我理解得很好,你确实在寻找一个groupingBy然后你必须通过对它们的int属性求和来对这些值进行分组。

groupingBy将为您提供Map<String, List<Query>>,但下游收集器(在这种情况下为Collectors.summingInt)将汇总int的所有Query值列表中的实例,生成Map<String, Integer>

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summingInt;
...

Map<String, Integer> map = 
    report.getQueries()
          .stream()
          .filter(q -> q.getComparisonFilter().isPresent())
          .filter(q -> q.getComparisonFilter().get().equals(view.getFilter().get()))
          .collect(groupingBy(q -> q.filterChoice.get(), summingInt(q -> q.queryOutput)));

请注意,您应该检查filterChoice Optional是否为空(可能添加另一个filter子句?)。您可以看到这个小gist的基本简化演示来说明原理。

同样,Optional类提供了equals的合理实现,因此filter子句可能如下所示:

.filter(q -> q.getComparisonFilter().equals(view.getFilter()))