Home > database >  How to calculate average from Collection of HashMap<String, Double>
How to calculate average from Collection of HashMap<String, Double>

Time:02-01

I have a Collection of HashMap<String, Duble> which I am getting from multimap. I want to calculate the average on Maps values and calculate which Map key is having minimum average. The data looks like that:

HashMap<A1, 2.0>
HashMap<A2, 1.0>
HashMap<A1, 3.0>
HashMap<A2, 1.0>

I am not getting the idea. Can someone give me a hint?

Adding some more data which show why I am using MultiMap.

{‘Gateway’:’ G1’, ‘Device’: ‘D1’,’position’:{‘rssi’: 1}},
{‘Gateway’:’ G2’, ‘Device’: ‘D1’,’position’:{‘rssi’: 3}},
{‘Gateway’:’ G1’, ‘Device’: ‘D1’,’position’:{‘rssi’: 2}},
{‘Gateway’:’ G2’, ‘Device’: ‘D1’,’position’:{‘rssi’: 5}},
{‘Gateway’:’ G1’, ‘Device’: ‘D1’,’position’:{‘rssi’: 4}},
{‘Gateway’:’ G2’, ‘Device’: ‘D1’,’position’:{‘rssi’: 6}},
..
{‘Gateway’:’ G1’, ‘Device’: ‘D2’,’position’:{‘rssi’: 3}},
{‘Gateway’:’ G2’, ‘Device’: ‘D2’,’position’:{‘rssi’: 2}},

Actually, this is a series of data coming to my endpoint, I need to calculate Which device is staying more at which Gateway. First I need to add Devices into MultiMap and then Gateway with position into Map. In the end I want to calculate the average like that:

D1-> G1: {1,2,4} => 7/3 = 2.3 
D1-> G2: {3,5,6} => 14/3 = 4.6

CodePudding user response:

Assuming your collection of maps is something similar to this:

List<Map<String, Double>> mapList = List.of(
        Map.of("A1", 2.0),
        Map.of("A2", 1.0),
        Map.of("A1", 3.0),
        Map.of("A2", 1.0));

You can just stream over the list (collection), stream over the entries of each map flatmaping to a stream of entries, collect to a new map grouping by key and averaging value, stream over the resulting map and find the min using a comparator by value:

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

....



Entry<String, Double> entryWithMinAvg =
        mapList.stream()
               .flatMap(m -> m.entrySet().stream())
               .collect(Collectors.groupingBy(Entry::getKey, Collectors.averagingDouble(Entry::getValue)))
               .entrySet()
               .stream()
               .min(Entry.comparingByValue())
               .get();

System.out.println(entryWithMinAvg);

CodePudding user response:

The most straightforward multi-map implementation using standard Java collections is a Map<K,List<V>> - i.e. a map from each key to a list of values for that key. It is relatively trivial to add to it using

Map<String,List<Double>> multimap;
multimap.computeIfAbsent(key, k -> new ArrayList<>()).add(value);

Finding the key with the minimum average is also trivial using a comparator to compare the averages:

Comparator<String> compareAverageKeys = Comparator.comparingDouble(
    k -> multimap.get(k).stream().mapToDouble(v -> v).average().get());
multimap.keys().stream().min(compareAverageKeys);

If your only reason for creating the collection is to find the average then you could just keep the stats rather than the keys:

Map<String,DoubleSummaryStatistics> stats;

stats.computeIfAbsent(key, k -> new DoubleSummaryStatistics()).add(value);

Then finding the key with the minimum is much simpler and more efficient:

stats.keys().stream().min(Comparator.comparingDouble(k -> stats.get(k).getAverage());
  • Related