使用流计算值的百分比

Calculate percentage of a value using stream

我正在尝试弄清楚如何在使用 stream 时计算列表中特定值的百分比。

我的对象 getTag 可以取值 GY,我想计算 G:s 在列表中的百分比。另一个对象是 getDateTime,其形式为 1946-01-12

我有条件 filter(weather -> !weather.getDateTime().isAfter(dateTo) && !weather.getDateTime().isBefore(dateFrom)) 因为我只想要用户输入的两个日期之间的百分比。

因此每个 DateTime 值对应于 GY。我用Collectors.counting()计算了GY的频率,但是我怎样才能得到百分比?

Map<String, Long> percentage = weatherData.stream()
        .filter(weather -> !weather.getDateTime().isAfter(dateTo) && !weather.getDateTime().isBefore(dateFrom))
        .collect(Collectors.groupingBy(Weather::getTag, Collectors.counting()));

如果将您关心的项目 ("G") 映射为 1,将其他所有项目映射为 0,则平均值为 "G" 在流中的百分比。

double pctG = list.stream()
    .mapToInt(obj -> obj.getTag().equals("G") ? 1 : 0)
    .summaryStatistics()
    .getAverage();

和Java13,可以用teeing()收集器按tag统计元素,过滤后的元素总数,整理将组数除以总数:

Map<String, Double> fractions = weatherData.stream()
        .filter(...)
        .collect(
            Collectors.teeing(
                Collectors.groupingBy(Weather::getTag, Collectors.counting()),
                Collectors.counting(),
                YourClass::scale));

其中 scale() 函数将每个组除以总数:

static <T> Map<T, Double> scale(Map<? extends T, Long> counts, long total) {
    return counts.entrySet().stream().
        .collect(Collectors.toMap(e -> e.getKey(), ((double) e.getValue()) / total));
}