Java 8 stream Map<String, List<String>> sum of values for each key

Map<String, Double> finalResult = inputMap.entrySet()
        .stream()
        .collect(Collectors.toMap(
                Entry::getKey,
                e -> e.getValue()
                      .stream()
                      .mapToDouble(str -> computeScore(str))
                      .sum()));

Above code iterates over the map and creates a new map with same keys & before putting the values, it first iterates over each value - which is a list, computes score via calling computeScore() over each list element and then sums the scores collected to be put in the value.


You could also use the forEach method along with the stream API to yield the result you're seeking.

Map<String, Double> resultSet = new HashMap<>();
inputMap.forEach((k, v) -> resultSet.put(k, v.stream()
            .mapToDouble(s -> computeScore(s)).sum()));

s -> computeScore(s) could be changed to use a method reference i.e. T::computeScore where T is the name of the class containing computeScore.


How about this one:

Map<String, Double> finalResult = inputMap.entrySet()
    .stream()
    .map(entry -> new AbstractMap.SimpleEntry<String, Double>(   // maps each key to a new
                                                                 // Entry<String, Double>
        entry.getKey(),                                          // the same key
        entry.getValue().stream()                             
            .mapToDouble(string -> computeScore(string)).sum())) // List<String> mapped to 
                                                                 // List<Double> and summed
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue));  // collected by the same 
                                                                 // key and a newly 
                                                                 // calulcated value

The version above could be merged to the single collect(..) method:

Map<String, Double> finalResult = inputMap.entrySet()
    .stream()
    .collect(Collectors.toMap(
         Entry::getKey,                        // keeps the same key
         entry -> entry.getValue()
                       .stream()               // List<String> -> Stream<String>
                                               // then Stream<String> -> Stream<Double>
                       .mapToDouble(string -> computeScore(string)) 
                       .sum()));               // and summed 

The key parts:

  • collect(..) performs a reduction on the elements using a certain strategy with a Collector.
  • Entry::getKey is a shortcut for entry -> entry.getKey. A function for mapping the key.
  • entry -> entry.getValue().stream() returns the Stream<String>
  • mapToDouble(..) returns the DoubleStream. This has an aggregating operation sum(..) which sums the elements - together creates a new value for the Map.