Hruday
Hruday

Reputation: 63

java stream List<Map<String,Double>> need average based on the string

I need the average of the list

    List<Measurement> measurements = new ArrayList<>();

    Measurement m1 = new Measurement();
    Map<String,Double> map1 = new HashMap<>();
    map1.put("age",18.0);
    map1.put("score",88.0);
    map1.put("rating",5.0);
    m1.setMetric(map1);

    Measurement m2 = new Measurement();
    Map<String,Double> map2 = new HashMap<>();
    map2.put("age",21.0);
    map2.put("score",null);
    map2.put("rating",23.0);
    m2.setMetric(map2);

    Measurement m3 = new Measurement();
    Map<String,Double> map3 = new HashMap<>();
    map3.put("age",31.0);
    map3.put("score",32.0);
    map3.put("rating",null );
    m3.setMetric(map3);

    measurements.add(m1);
    measurements.add(m2);
    measurements.add(m3);

How do I get the average Age for the above list of maps. Also Average Score by ignoring the null values.

Any help would be really appreciated. I am struggling to fix since 3 days. Thank you in advance.

Upvotes: 3

Views: 1118

Answers (3)

Boken
Boken

Reputation: 5362

for such Measurement class:

class Measurement {

    Map<String, Double> map;

    public void setMetric(Map<String, Double> map) {
        this.map = map;
    }
}

How to find avarage "age" (using stream):

Double averageAge = measurements.stream()
        .collect(Collectors.averagingDouble(node -> node.map.getOrDefault("age", 0D)));

And stream for nullable "score":

How to find avarage "age" (using stream) with null check:

Double averageAge = measurements.stream()
        .filter(node -> node.map.get("score") != null)
        .collect(Collectors.averagingDouble(node -> node.map.getOrDefault("score", 0D)));

In above code you have node.map where map is field form class. Can be replaced with getMap() or different method returning value (which you are set by setMetric())

How to find avarage "age" (using loop):

Double average = 0D;
for (Measurement measure : measurements) {
    average += measure.map.getOrDefault("age", 0D);
}
average /= measurements.size();

How to find avarage "score" (using loop) with null check:

Double average = 0D;
int counter = 0;
for (Measurement measure : measurements) {
    if (measure.map.get("score") != null) {
        average += measure.map.getOrDefault("score", 0D);
        counter++;
    }
}
average /= counter;

How to find the smallest "score" (using loop) with null check:

Double min = Double.MAX_VALUE;

for (Measurement measure : measurements) {
    Double score = measure.map.get("score");
    if (score != null && score < min) {
        min = score;
    }
}

System.out.println(min);

How to find the biggest "age" (using streams)

Double max = measurements.stream()
        .filter(node -> node.map.get("score") != null)
        .mapToDouble(node -> node.map.get("score"))
        .max()
        .orElse(0.0);

Upvotes: 0

ernest_k
ernest_k

Reputation: 45329

You can compute the average values for each map key using:

Map<String, Double> result = Stream.of(m1, m2, m3)
        .flatMap(m -> m.getMap1().entrySet().stream()
                       .filter(e -> e.getValue() != null))
        .collect(Collectors.groupingBy(e -> e.getKey(), 
                Collectors.averagingDouble(e -> e.getValue())));

And the output for your test data is {score=60.0, rating=14.0, age=23.333333333333332}

Upvotes: 0

Naman
Naman

Reputation: 31968

You can get an average of age as:

Double averageAge = measurements.stream()
        .flatMap(a -> a.getMetric().entrySet().stream())
        .filter(a -> a.getKey().equals("age"))
        .mapToDouble(Map.Entry::getValue)
        .average()
        .orElse(Double.NaN);

and similarly, averaging score would require an additional filter condition to exclude null values.

Upvotes: 1

Related Questions