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!
sum() The Stream API provides us with the mapToInt() intermediate operation, which converts our stream to an IntStream object. This method takes a mapper as a parameter, which it uses to do the conversion, then we can call the sum() method to calculate the sum of the stream's elements.
So you simply make this: sum=sum+num; for the cycle. For example sum is 0, then you add 5 and it becomes sum=0+5 , then you add 6 and it becomes sum = 5 + 6 and so on.
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()))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With