WeightedMeanAndSum.java

  1. package org.opentrafficsim.base;

  2. import java.util.Collection;
  3. import java.util.Iterator;
  4. import java.util.Map;
  5. import java.util.Map.Entry;
  6. import java.util.function.Function;

  7. import org.djutils.exceptions.Throw;

  8. /**
  9.  * Utility to calculate a weighted mean and/or sum. This can be used as part of a process or loop with information being
  10.  * accumulated in the object. This is even a memory friendly method as this class only stores 2 double values internally.
  11.  * <p>
  12.  * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  13.  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  14.  * <p>
  15.  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 8 okt. 2018 <br>
  16.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  17.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  18.  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  19.  * @param <V> value type
  20.  * @param <W> weight type
  21.  */
  22. public class WeightedMeanAndSum<V extends Number, W extends Number>
  23. {
  24.     /** Cumulative numerator of weighted mean fraction, i.e. weighted sum. */
  25.     private double numerator;

  26.     /** Cumulative denominator of weighted mean fraction, i.e. sum of weights. */
  27.     private double denominator;

  28.     /**
  29.      * Constructor.
  30.      */
  31.     public WeightedMeanAndSum()
  32.     {
  33.         //
  34.     }

  35.     /**
  36.      * Returns the weighted mean of available data.
  37.      * @return double; weighted mean of available data
  38.      */
  39.     public final double getMean()
  40.     {
  41.         return this.numerator / this.denominator;
  42.     }

  43.     /**
  44.      * Returns the weighted sum of available data.
  45.      * @return double; weighted sum of available data
  46.      */
  47.     public final double getSum()
  48.     {
  49.         return this.numerator;
  50.     }

  51.     /**
  52.      * Returns the sum of the weights.
  53.      * @return double; sum of the weights
  54.      */
  55.     public final double getWeightSum()
  56.     {
  57.         return this.denominator;
  58.     }

  59.     /**
  60.      * Adds a value with weight.
  61.      * @param value V; value
  62.      * @param weight W; weight
  63.      * @return this WeightedMeanAndSum for method chaining
  64.      */
  65.     public final WeightedMeanAndSum<V, W> add(final V value, final W weight)
  66.     {
  67.         this.numerator += weight.doubleValue() * value.doubleValue();
  68.         this.denominator += weight.doubleValue();
  69.         return this;
  70.     }

  71.     /**
  72.      * Adds a weighted value for each element. Note that iteration order is pivotal in correct operations. This method should
  73.      * not be used with instances of {@code HashMap} or {@code HashSet}.
  74.      * @param values Iterable&lt;V&gt;; values
  75.      * @param weights Iterable&lt;W&gt;; weights
  76.      * @return this WeightedMeanAndSum&lt;V, W&gt; for method chaining
  77.      * @throws IllegalArgumentException if the number of values and weights are unequal
  78.      */
  79.     public final WeightedMeanAndSum<V, W> add(final Iterable<V> values, final Iterable<W> weights)
  80.     {
  81.         Iterator<V> itV = values.iterator();
  82.         Iterator<W> itW = weights.iterator();
  83.         while (itV.hasNext())
  84.         {
  85.             Throw.when(!itW.hasNext(), IllegalArgumentException.class, "Unequal number of values and weights.");
  86.             add(itV.next(), itW.next());
  87.         }
  88.         Throw.when(itW.hasNext(), IllegalArgumentException.class, "Unequal number of values and weights.");
  89.         return this;
  90.     }

  91.     /**
  92.      * Adds a weighted value for each element.
  93.      * @param values V[]; values
  94.      * @param weights W[]; weights
  95.      * @return this WeightedMeanAndSum&lt;V, W&gt; for method chaining
  96.      */
  97.     public final WeightedMeanAndSum<V, W> add(final V[] values, final W[] weights)
  98.     {
  99.         Throw.when(values.length != weights.length, IllegalArgumentException.class, "Unequal number of values and weights.");
  100.         for (int i = 0; i < values.length; i++)
  101.         {
  102.             add(values[i], weights[i]);
  103.         }
  104.         return this;
  105.     }

  106.     /**
  107.      * Adds each weighted value from a map.
  108.      * @param map Map&lt;V, W&gt;; map
  109.      * @return this WeightedMeanAndSum&lt;V, W&gt; for method chaining
  110.      */
  111.     public final WeightedMeanAndSum<V, W> add(final Map<V, W> map)
  112.     {
  113.         for (Entry<V, W> entry : map.entrySet())
  114.         {
  115.             add(entry.getKey(), entry.getValue());
  116.         }
  117.         return this;
  118.     }

  119.     /**
  120.      * Adds each value with a weight given by a function.
  121.      * @param collection Collection&lt;V&gt;; values
  122.      * @param weights Function&lt;V, W&gt;; weights
  123.      * @return this WeightedMeanAndSum&lt;V, W&gt; for method chaining
  124.      */
  125.     public final WeightedMeanAndSum<V, W> add(final Collection<V> collection, final Function<V, W> weights)
  126.     {
  127.         for (V v : collection)
  128.         {
  129.             add(v, weights.apply(v));
  130.         }
  131.         return this;
  132.     }

  133.     /**
  134.      * Adds each value with a weight given by a function.
  135.      * @param collection Collection&lt;S&gt;; collection of source objects
  136.      * @param values Function&lt;S, V&gt;; values
  137.      * @param weights Function&lt;S, W&gt;; weights
  138.      * @param <S> type of source object
  139.      * @return this WeightedMeanAndSum&lt;V, W&gt; for method chaining
  140.      */
  141.     public final <S> WeightedMeanAndSum<V, W> add(final Collection<S> collection, final Function<S, V> values,
  142.             final Function<S, W> weights)
  143.     {
  144.         for (S s : collection)
  145.         {
  146.             add(values.apply(s), weights.apply(s));
  147.         }
  148.         return this;
  149.     }
  150. }