package org.opentrafficsim.base; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.function.Function; import org.djutils.exceptions.Throw; /** * Utility to calculate a weighted mean and/or sum. This can be used as part of a process or loop with information being * accumulated in the object. This is even a memory friendly method as this class only stores 2 double values internally. *

* Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License. *

* @version $Revision$, $LastChangedDate$, by $Author$, initial version 8 okt. 2018
* @author Alexander Verbraeck * @author Peter Knoppers * @author Wouter Schakel * @param value type * @param weight type */ public class WeightedMeanAndSum { /** Cumulative numerator of weighted mean fraction, i.e. weighted sum. */ private double numerator; /** Cumulative denominator of weighted mean fraction, i.e. sum of weights. */ private double denominator; /** * Constructor. */ public WeightedMeanAndSum() { // } /** * Returns the weighted mean of available data. * @return double; weighted mean of available data */ public final double getMean() { return this.numerator / this.denominator; } /** * Returns the weighted sum of available data. * @return double; weighted sum of available data */ public final double getSum() { return this.numerator; } /** * Returns the sum of the weights. * @return double; sum of the weights */ public final double getWeightSum() { return this.denominator; } /** * Adds a value with weight. * @param value V; value * @param weight W; weight * @return this WeightedMeanAndSum for method chaining */ public final WeightedMeanAndSum add(final V value, final W weight) { this.numerator += weight.doubleValue() * value.doubleValue(); this.denominator += weight.doubleValue(); return this; } /** * Adds a weighted value for each element. Note that iteration order is pivotal in correct operations. This method should * not be used with instances of {@code HashMap} or {@code HashSet}. * @param values Iterable<V>; values * @param weights Iterable<W>; weights * @return this WeightedMeanAndSum<V, W> for method chaining * @throws IllegalArgumentException if the number of values and weights are unequal */ public final WeightedMeanAndSum add(final Iterable values, final Iterable weights) { Iterator itV = values.iterator(); Iterator itW = weights.iterator(); while (itV.hasNext()) { Throw.when(!itW.hasNext(), IllegalArgumentException.class, "Unequal number of values and weights."); add(itV.next(), itW.next()); } Throw.when(itW.hasNext(), IllegalArgumentException.class, "Unequal number of values and weights."); return this; } /** * Adds a weighted value for each element. * @param values V[]; values * @param weights W[]; weights * @return this WeightedMeanAndSum<V, W> for method chaining */ public final WeightedMeanAndSum add(final V[] values, final W[] weights) { Throw.when(values.length != weights.length, IllegalArgumentException.class, "Unequal number of values and weights."); for (int i = 0; i < values.length; i++) { add(values[i], weights[i]); } return this; } /** * Adds each weighted value from a map. * @param map Map<V, W>; map * @return this WeightedMeanAndSum<V, W> for method chaining */ public final WeightedMeanAndSum add(final Map map) { for (Entry entry : map.entrySet()) { add(entry.getKey(), entry.getValue()); } return this; } /** * Adds each value with a weight given by a function. * @param collection Collection<V>; values * @param weights Function<V, W>; weights * @return this WeightedMeanAndSum<V, W> for method chaining */ public final WeightedMeanAndSum add(final Collection collection, final Function weights) { for (V v : collection) { add(v, weights.apply(v)); } return this; } /** * Adds each value with a weight given by a function. * @param collection Collection<S>; collection of source objects * @param values Function<S, V>; values * @param weights Function<S, W>; weights * @param type of source object * @return this WeightedMeanAndSum<V, W> for method chaining */ public final WeightedMeanAndSum add(final Collection collection, final Function values, final Function weights) { for (S s : collection) { add(values.apply(s), weights.apply(s)); } return this; } }