Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 - How to sum all List element in a Map of Lists

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.

like image 613
horus Avatar asked Feb 03 '15 15:02

horus


People also ask

How will you get the sum of all numbers present in a List using Java 8?

Using Stream.collect() asList(1, 2, 3, 4, 5); Integer sum = integers. stream() . collect(Collectors. summingInt(Integer::intValue));

How do you sum a value on a map?

To get the sum of values we can use IntStream. sum() as follows for integer data type. int sum = map. values().

How do you sum a List in Java?

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.


Video Answer


1 Answers

You have to be aware that you can combine Collectors. 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;
  })));
like image 54
Holger Avatar answered Oct 12 '22 22:10

Holger