Java Stream Maximum Value From Average

Viewed 262

I have to get the Maximum average temperature's country name.

I have used following to get the average temperatures

 this.getTemperatures()
                .stream()
                .collect(Collectors.groupingBy(Temperature::getCountry,
                        Collectors.averagingDouble(Temperature::getAverageTemperature)))

How can I get the maximum or minimum average country name out of this average temperatures list?

4 Answers

I don't like this very much because a lot of the code is repeated, but it will work. I can't work out a way to avoid the repetition without making the code worse.

This also iterates all of the map entries twice but given that there are only 195 countries, we're talking about a maximum of 195 extra iterations (if you have measurements for every one), and that's a completely negligible amount for a CPU.

String max = countryToAvgTemp.entrySet().stream()      //stream all entries
    .max(Map.Entry.comparingByValue())                 //get the max by comparing entry value
    .map(Map.Entry::getKey)                            //grab the key   
    .orElseThrow(() -> new RuntimeException("No max")); //e.g. if the list is empty

String min = countryToAvgTemp.entrySet().stream()
    .min(Map.Entry.comparingByValue())
    .map(Map.Entry::getKey)
    .orElseThrow(() -> new RuntimeException("No min"));

If you only want to iterate once, you could write your own collector which returns something like a MinMax<String>. I wrote one but the code wasn't great. Better to keep it simple.

Use

Collections.min(temperatureMap.entrySet(), Comparator.comparingInt(Map.Entry::getValue)).getValue()

and

Collections.max(temperatureMap.entrySet(),  Comparator.comparingInt(Map.Entry::getValue)).getValue()

If you want get the maximum or minimum average country name,you can sort the temperatures list and then get the first and last element。But your work do not need sorted list,it is not a good method,@Michael's method is very good for you.

       List<Temperature> temperatures = Arrays.asList(
                new Temperature("a",10),
                new Temperature("b",11),
                new Temperature("c",12),
                new Temperature("d",13),
                new Temperature("e",14),
                new Temperature("f",15),
                new Temperature("g",16),
                new Temperature("h",17));

        temperatures = temperatures.stream().sorted(new Comparator<Temperature>() {
            @Override
            public int compare(Temperature o1, Temperature o2) {
                return (int) (o1.getAverageTemperature() - o2.getAverageTemperature());
            }
        }).collect(Collectors.toList());

        String min = temperatures.get(0).getCountry();
        String max = temperatures.get(temperatures.size()-1).getCountry();

You can try DoubleSummaryStatistics:

this.getTemperatures()
            .stream()
            .collect(Collectors.groupingBy(Temperature::getCountry,
                    Collectors.summarizingDouble(Temperature::getAverageTemperature)));

this will return a map:

Map<Country, DoubleSummaryStatistics>

So with DoubleSummaryStatistics, you can get count, sum, min, max, average of each country

Related