///////////////////////////////////////////////////////////////////////////// // // Project ProjectForge Community Edition // www.projectforge.org // // Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de) // // ProjectForge is dual-licensed. // // This community edition is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation; version 3 of the License. // // This community edition is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General // Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, see http://www.gnu.org/licenses/. // ///////////////////////////////////////////////////////////////////////////// package org.projectforge.statistics; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /** * @author Kai Reinhard (k.reinhard@micromata.de) * */ public abstract class AbstractAggregatedValues<T> { protected final List<T> values = new LinkedList<T>(); protected final List<T> weights = new LinkedList<T>(); protected boolean averageDirty, weightedAverageDirty; protected T average, weightedAverage; /** * @return this for chaining. */ public AbstractAggregatedValues<T> clear() { this.values.clear(); return this; } /** * @param value * @return this for chaining. */ public AbstractAggregatedValues<T> add(final T value) { values.add(value); averageDirty = weightedAverageDirty = true; return this; } /** * @param value * @return this for chaining. */ public AbstractAggregatedValues<T> add(final T value, final T weight) { values.add(value); weights.add(weight); averageDirty = weightedAverageDirty = true; return this; } /** * @return The mean value of all entries. */ public T getAverage() { if (average == null || averageDirty == true) { T sum = getZero(); if (values.size() == 0) { average = sum; } else { for (final T value : values) { sum = sum(sum, value); } average = divide(sum, convert(values.size())); } averageDirty = false; } return average; } /** * @return The weighted mean value of all entries. */ public T getWeightedAverage() { if (weightedAverage == null || weightedAverageDirty == true) { if (weights.size() != values.size()) { throw new IllegalArgumentException( "Size of weights not equals size of values, may-be add(value, weight) wasn't called at least once!"); } T sum = getZero(); T weightSum = getZero(); if (values.size() == 0) { weightedAverage = sum; } else { final Iterator<T> valuesIt = values.iterator(); final Iterator<T> weightsIt = weights.iterator(); while (valuesIt.hasNext() == true) { final T value = valuesIt.next(); final T weight = weightsIt.next(); sum = sum(sum, multiply(value, weight)); weightSum = sum(weightSum, weight); } if (isZero(weightSum) == true) { weightedAverage = getZero(); } else { weightedAverage = divide(sum, weightSum); } } weightedAverageDirty = false; } return weightedAverage; } public int getNumberOfValues() { return values.size(); } protected abstract T getZero(); protected abstract T sum(T value1, T value2); protected abstract T convert(int value); protected abstract T divide(T value, T divisor); protected abstract T multiply(T value1, T value2); protected abstract boolean isZero(T value); }