I have a Map of Lists of a particular Object and I want to add all the elements of the lists based on a particular instance variable.
My Object:
class Risk{
Integer id, riskValue, totRisk=0;
String name;
Integer getId(){
return id;
}
Risk(Object[] result){
id=(Integer)result[0];
riskValue=(Integer)result[1];
name=(String)result[3];
}
}
I get from the Database a List of Arrays of type object:
List< Object[] > results=getResults();
I use Java 8 to group my Data by ID, because I want to SUM by riskValue
all the objects of type Risk
having the same id
.
This is what I do:
List<Risk> risks=results.stream().map(Risk::new).collect(Collectors.toList());
Map<Integer, List<Risk>> byId=risks.stream.collect(Collectors.groupingBy(Risk::getId));
At this point I have all my Risk objects grouped by ID. And I want for each list to sum all the objects by riskValue
and have the total in the variable totRisk
How to compute in the variable totRisk
the total of the variables riskValue
in each List?
Note1: I want to do it using Java 8, I know how to do it using Java 7 and below.
Note2: Perhaps it's also possible to do it in one go, by not having first to group by ID. What I want to achieve is to sum all the objects with the same ID in the original List<Object[]> results
. If it can be done with only one statement is even better.
Using Stream.collect() asList(1, 2, 3, 4, 5); Integer sum = integers. stream() . collect(Collectors. summingInt(Integer::intValue));
To get the sum of values we can use IntStream. sum() as follows for integer data type. int sum = map. values().
A simple solution to calculate the sum of all elements in a List is to convert it into IntStream and call sum() to get the sum of elements in the stream. There are several ways to get IntStream from Stream<Integer> using mapToInt() method.
You have to be aware that you can combine Collector
s. See Collectors.groupingBy(Function,Collector)
Map<Integer, Integer> byId=risks.stream.collect(
Collectors.groupingBy(Risk::getId, Collectors.summingInt(Risk::getRiskValue)));
You can also combine it with the first operation:
Map<Integer, Integer> byId=results.stream().map(Risk::new).collect(
Collectors.groupingBy(Risk::getId, Collectors.summingInt(Risk::getRiskValue)));
Note that I assume that you have a method getRiskValue()
in your class Risk
, otherwise you have to replace Risk::getRiskValue
with a lambda expression r -> r.riskValue
to access the field, however, having getter methods is always recommended.
The result maps from id to total.
After reading your question again, I noticed that you actually want to sum up riskValue
and store it within totRisk
of each (?) Risk
instance. This is a bit more complicated as it doesn’t fit the common usage pattern:
Map<Integer, List<Risk>> byId=results.stream().map(Risk::new).collect(
Collectors.groupingBy(Risk::getId, Collectors.collectingAndThen(
Collectors.toList(), l-> {
int total=l.stream().collect(Collectors.summingInt(r -> r.riskValue));
l.forEach(r->r.totRisk=total);
return l;
})));
at this point we really should switch to using import static java.util.stream.Collectors.*;
:
Map<Integer, List<Risk>> byId=results.stream().map(Risk::new).collect(
groupingBy(Risk::getId, collectingAndThen(toList(), l-> {
int total=l.stream().collect(summingInt(r -> r.riskValue));
l.forEach(r->r.totRisk=total);
return l;
})));
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