Map<Double, Integer>
の加重平均を計算するにはどうすればよいですか。Integer値は、Double値の平均値です。 例えば:地図以下たエレメント:Java 8ストリームで加重平均を計算する
- (0.7、100)//値は0.7であり、重量が100
- で(0.5、200)
- (0.3、300)
- (0.0、 400)
私は、Java 8ストリームを使用して次の式を適用することを検討していますが、分子と分母を一緒に計算して同時に保存する方法は不明です。ここで還元を使う方法は?
Map<Double, Integer>
の加重平均を計算するにはどうすればよいですか。Integer値は、Double値の平均値です。 例えば:地図以下たエレメント:Java 8ストリームで加重平均を計算する
私は、Java 8ストリームを使用して次の式を適用することを検討していますが、分子と分母を一緒に計算して同時に保存する方法は不明です。ここで還元を使う方法は?
あなたはこの作業のために、独自のコレクターを作成することができます。
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
)。これは、収集プロセス中に分子と分母を格納するヘルパーローカルクラスを使用します。エントリーが受け入れられるたびに、分子はその値にその重みを掛けた結果で増加し、分母は加重と共に増加する。フィニッシャは、この2つの除算を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));
これと素晴らしい説明もありがとう。私はカスタムコレクターについてもっと詳しく読むつもりです。 –
あなたがマップの加重平均を算出するために、この手順を使用することができます。マップエントリのキーには値が含まれている必要があり、マップエントリの値には重みが含まれている必要があります。
/**
* Calculates the weighted average of a map.
*
* @throws ArithmeticException If divide by zero happens
* @param map A map of values and weights
* @return The weighted average of the map
*/
static Double calculateWeightedAverage(Map<Double, Integer> map) throws ArithmeticException {
double num = 0;
double denom = 0;
for (Map.Entry<Double, Integer> entry : map.entrySet()) {
num += entry.getKey() * entry.getValue();
denom += entry.getValue();
}
return num/denom;
}
ユースケースを見るためにユニットテストを見ることができます。
/**
* Tests our method to calculate the weighted average.
*/
@Test
public void testAveragingWeighted() {
Map<Double, Integer> map = new HashMap<>();
map.put(0.7, 100);
map.put(0.5, 200);
Double weightedAverage = calculateWeightedAverage(map);
Assert.assertTrue(weightedAverage.equals(0.5666666666666667));
}
あなたはユニットテストのためにこれらの輸入が必要になります。
import org.junit.Assert;
import org.junit.Test;
あなたはコードのこれらの輸入が必要になります。
import java.util.HashMap;
import java.util.Map;
私はそれが役に立てば幸い。
[Collectors.averagingDouble'](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#averagingDouble-java.util.function)を確認しましたか。 .ToDoubleFunction-)メソッド? – Aaron