使用 Java 8 流计算加权平均值 [英] Calculate weighted average with Java 8 streams

查看:60
本文介绍了使用 Java 8 流计算加权平均值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何计算 Map 的加权平均值,其中 Integer 值是要平均的 Double 值的权重.例如:地图有以下元素:

How do I go about calculating weighted mean of a Map<Double, Integer> where the Integer value is the weight for the Double value to be averaged. eg: Map has following elements:

  1. (0.7, 100)//值为 0.7,权重为 100
  2. (0.5, 200)
  3. (0.3, 300)
  4. (0.0, 400)

我希望使用 Java 8 流应用以下公式,但不确定如何同时计算分子和分母并同时保留它.这里如何使用reduction?

I am looking to apply the following formula using Java 8 streams, but unsure how to calculate the numerator and denominator together and preserve it at the same time. How to use reduction here?

推荐答案

您可以为此任务创建自己的收集器:

You can create your own collector for this task:

static <T> Collector<T,?,Double> averagingWeighted(ToDoubleFunction<T> valueFunction, ToIntFunction<T> weightFunction) {
    class Box {
        double num = 0;
        long denom = 0;
    }
    return Collector.of(
             Box::new,
             (b, e) -> { 
                 b.num += valueFunction.applyAsDouble(e) * weightFunction.applyAsInt(e); 
                 b.denom += weightFunction.applyAsInt(e);
             },
             (b1, b2) -> { b1.num += b2.num; b1.denom += b2.denom; return b1; },
             b -> b.num / b.denom
           );
}

此自定义收集器采用两个函数作为参数:一个是返回值以用于给定流元素的函数(作为 ToDoubleFunction),另一个返回权重(作为 ToIntFunction).它使用一个辅助本地类在收集过程中存储分子和分母.每次接受一个条目时,分子会随着该值与其权重相乘的结果而增加,而分母会随着权重而增加.然后完成器将两者的除法返回为 Double.

This custom collector takes two functions as parameter: one is a function returning the value to use for a given stream element (as a ToDoubleFunction), and the other returns the weight (as a ToIntFunction). It uses a helper local class storing the numerator and denominator during the collecting process. Each time an entry is accepted, the numerator is increased with the result of multiplying the value with its weight, and the denominator is increased with the weight. The finisher then returns the division of the two as a Double.

示例用法如下:

Map<Double,Integer> map = new HashMap<>();
map.put(0.7, 100);
map.put(0.5, 200);

double weightedAverage =
  map.entrySet().stream().collect(averagingWeighted(Map.Entry::getKey, Map.Entry::getValue));

这篇关于使用 Java 8 流计算加权平均值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆