Sum attribute of object with Stream API
java, java-8, java-stream
Solution
If I understand well, you are indeed looking for a `groupingBy` and then you have to group the values by summing their int property.
The `groupingBy` will give you a `Map<String, List<Query>>` but then the downstream collector (`Collectors.summingInt` in this case) will sum all the `int` values of the `Query` instances in the list, resulting in a `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)));
Note that you should check whether the `filterChoice` Optional is not empty (maybe add another `filter` clause?). You can see this small gist for a basic and simplified demo to illustrate the principle.
Also the `Optional` class provide a sensible implementation of `equals` so the filter clause could looks like this:
.filter(q -> q.getComparisonFilter().equals(view.getFilter()))
Problem
I currently have the following situation: I have got a `Report` object which can contain multiple `Query` objects. The `Query` objects have properties: `Optional<Filter> comparisonFilter`, `Optional<String> filterChoice` and `int queryOutput`. Not every query has a comparison filter, so I first check on that. Then, I make sure I get the queries for a particular filter (which is not the problem here, so I will not discuss this in detail). Every filter has some choices, of which the number of choices is variable. Here is an example of the input (these `Query` objects all have the same 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 ``` Now, I would like to sum the query outputs for every unique choice. I currently have this code: ``` 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 }); ``` I could do this by creating a `Map<String, Integer>`, where the key is the choice and the value is the query input. But then I would need to loop through the `Map` again to use the value for something (which is not important here). The output should be like this: ``` Choice: 'First' -- Summed Output: 15 Choice: 'Second' -- Summed Output: 25 Choice: 'Third' -- Summed Output: 10 ``` But I would like to use this 'Summed Output' directly in a `forEach` on the stream, but if this is not possible or practical anymore, I am okay with that. I would like to do this the 'Java 8'-way, but I can not seem to find out how. So my question is: Is it possible to do this shorter with the new Stream API? Note: If anyone has some ideas about how I could make this question more general (maybe a better title and some generalizations), please let me know!