Чтобы сократить формулировку задачи на меньший блок, вы могли бы рассмотреть еще один подход - анализ year
температуры и вычисление для них дельты, а затем average
. Это должно быть сделано для всех значений типа Map<Integer, Double>
внутри внутреннего Map
в вашем вопросе. Это будет выглядеть примерно так:
Map<Integer, Double> unitOfWork = new HashMap<>(); // innermost map you've attained ('yearToAverageTemperature' map)
unitOfWork = unitOfWork.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
// the values sorted based on the year from a sorted map
List<Double> srtedValPerYear = new ArrayList<>(unitOfWork.values());
// average of deltas from the complete list
double avg = IntStream.range(0, srtedVal.size() - 1)
.mapToDouble(i -> (srtedVal.get(i + 1) - srtedVal.get(i)))
.average().orElse(Double.NaN);
Отметим, что это всего лишь среднее значение одной записи City
, равной <Year, AverageTemperature>
, вам нужно будет выполнить итерацию по всему вашему набору ключей City
и аналогично всем вашим наборам ключей Country
, чтобы получить исчерпывающие сведения. такие средние.
Дальнейшее перемещение этой единицы работы в метод, итерация по полной карте карт, это может быть выполнено как:
// The average of all cities in a country is the average of a country.
AtomicReference<Double> countryValAvg = new AtomicReference<>(0.0);
countriesMap.forEach((country, cityMap) -> {
// The average of all these deltas is the average annual temperature delta for a city.
AtomicReference<Double> cityAvgTemp = new AtomicReference<>((double) 0);
cityMap.forEach((city, yearMap) -> cityAvgTemp.set(cityAvgTemp.get() + averagePerCity(yearMap)));
double avgAnnualTempDeltaPerCity = cityAvgTemp.get() / cityMap.size();
countryValAvg.set(countryValAvg.get() + avgAnnualTempDeltaPerCity);
});
System.out.println(countryValAvg.get() / countriesMap.size());
где averagePerCity
- метод, который выполняет следующие действия:
double averagePerCity(Map<Integer, Double> unitOfWork) {
unitOfWork = unitOfWork.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
List<Double> srtedVal = new ArrayList<>(unitOfWork.values());
return IntStream.range(0, srtedVal.size() - 1)
.mapToDouble(i -> (srtedVal.get(i + 1) - srtedVal.get(i)))
.average().orElse(Double.NaN);
}
Примечание : В приведенном выше коде могут отсутствовать валидации, это просто для того, чтобы дать представление о том, как можно разбить полную проблему на более мелкие части и затем решить.
Edit1 : который может быть улучшен как :
// The average of all cities in a country is the average of a country.
AtomicReference<Double> countryValAvg = new AtomicReference<>(0.0);
countriesMap.forEach((country, cityMap) -> {
// The average of all these deltas is the average annual temperature delta for a city.
double avgAnnualTempDeltaPerCity = cityMap.values()
.stream()
.mapToDouble(Quick::averagePerCity) // Quick is my class name
.average()
.orElse(Double.NaN);
countryValAvg.set(countryValAvg.get() + avgAnnualTempDeltaPerCity);
});
System.out.println(countryValAvg.get() / countriesMap.size());
Редактировать2 : и далее до
double avgAnnualTempDeltaPerCity = countriesMap.values().stream()
.mapToDouble(cityMap -> cityMap.values()
.stream()
.mapToDouble(Quick::averagePerCity) // Quick is my class name
.average()
.orElse(Double.NaN))
.average().orElse(Double.NaN);