gpt4 book ai didi

Java 8 Streams 多重分组依据

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:52:32 24 4
gpt4 key购买 nike

我有这样的温度记录

dt        |AverageTemperature |AverageTemperatureUncertainty|City   |Country |Latitude|Longitude
----------+-------------------+-----------------------------+-------+--------+--------+---------
1963-01-01|-5.417000000000002 |0.5 |Karachi|Pakistan|57.05N |10.33E
1963-02-01|-4.7650000000000015|0.328 |Karachi|Pakistan|57.05N |10.33E
1964-01-01|-5.417000000000002 |0.5 |Karachi|Pakistan|57.05N |10.33E
1964-02-01|-4.7650000000000015|0.328 |Karachi|Pakistan|57.05N |10.33E
1965-01-01|11.417000000000002 |0.5 |Karachi|Pakistan|57.05N |10.33E
1965-02-01|12.7650000000000015|0.328 |Karachi|Pakistan|57.05N |10.33E

我必须将其解析为 POJO 并根据以下问题陈述计算平均增量:

Use the Streams API to calculate the average annual temperature delta for each country. To calculate delta the average temperature in 1900 would be subtracted from the average temperature in 1901 to obtain the delta from 1900 to 1901 for a particular city. The average of all these deltas is the average annual temperature delta for a city. The average of all cities in a country is the average of a country.

我的 Temperate POJO 看起来像下面有 getter 和 setter

public class Temperature {
private java.util.Date date;
private double averageTemperature;
private double averageTemperatureUncertainty;
private String city;
private String country;
private String latitude;
private String longitude;
}

我维护了一个温度列表,因为这个问题将使用流来解决。

为了计算增量,我尝试使用以下流,但我仍然无法计算实际增量,因为我必须计算平均国家增量,我已经对国家、城市和日期进行了分组。

Map<String, Map<String, Map<Integer, Double>>> countriesMap = this.getTemperatures().stream()
.sorted(Comparator.comparing(Temperature::getDate))
.collect(Collectors.groupingBy(Temperature::getCountry,
Collectors.groupingBy(Temperature::getCity,
Collectors.groupingBy
(t -> {
Calendar calendar = Calendar.getInstance();
calendar.setTime(t.getDate());
return calendar.get(Calendar.YEAR);
},
Collectors.averagingDouble(Temperature::getAverageTemperature)))));

为了计算增量,我们必须计算差异对于 Map<Integer, Double> .

为了计算差异,我想出了以下代码,但无法将以下代码与上面的代码联系起来

Stream.of(10d, 20d, 10d) //this is sample data that I that I get in `Map<Integer, Double>` of countriesMap
.map(new Function<Double, Optional<Double>>() {
Optional<Double> previousValue = Optional.empty();
@Override
public Optional<Double> apply(Double current) {
Optional<Double> value = previousValue.map(previous -> current - previous);
previousValue = Optional.of(current);
return value;
}
})
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println);

如何一次性使用流计算增量或如何对 countriesMap 执行流操作为了计算delta并实现上述问题陈述。?

最佳答案

要将问题陈述缩减为更小的 block ,您可以研究的另一种方法是通过 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 keyset 和类似的所有 Country键集以详尽地找出此类平均值。

进一步将这个工作单元移动到一个方法中,遍历整个 map 的 map ,这可能会完成为:

// 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:哪个could be improved further as :

// 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());

Edit2:进一步

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);

关于Java 8 Streams 多重分组依据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54132104/

24 4 0