All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hfg.util.collection.NumberMatrix Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.util.collection;


import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

//------------------------------------------------------------------------------
/**
 Sparse matrix for Numbers that calculated totals and percentages.
 
@author J. Alex Taylor, hairyfatguy.com
*/ //------------------------------------------------------------------------------ // com.hfg Library // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ public class NumberMatrix extends SparseMatrix { // Cached values private Constructor mValueStringConstructor; private Map mRowTotalMap; private Map mColTotalMap; private V mGrandTotal; //########################################################################## // CONSTRUCTORS //########################################################################## //-------------------------------------------------------------------------- public NumberMatrix() { super(); } //-------------------------------------------------------------------------- public NumberMatrix(int inInitialRowCapacity, int inInitialColCapacity) { super(inInitialRowCapacity, inInitialColCapacity); } //########################################################################## // PUBLIC METHODS //########################################################################## //-------------------------------------------------------------------------- /** * Increments the value in the specified cell by the specified amount. * * @param inRowKey the key of the selected row * @param inColKey the key of the selected column * @param inIncrementSize the amount by which to increment the value */ public void increment(RK inRowKey, CK inColKey, V inIncrementSize) { if (inIncrementSize != null) { V existingValue = get(inRowKey, inColKey); V newValue; if (null == existingValue) { newValue = inIncrementSize; } else { double total = existingValue.doubleValue() + inIncrementSize.doubleValue(); if (null == mValueStringConstructor) { setValueStringConstructorFromValue(existingValue); } newValue = instantiateValue(total); } put(inRowKey, inColKey, newValue); } } //-------------------------------------------------------------------------- public V getColTotal(CK inColKey) { V colTotal = null; if (null == mColTotalMap && CollectionUtil.hasValues(colKeySet())) { mColTotalMap = new HashMap<>(colKeySet().size()); for (CK colKey : colKeySet()) { double total = 0.0; for (RK rowKey : rowKeySet()) { V value = get(rowKey, colKey); if (null == mValueStringConstructor) { setValueStringConstructorFromValue(value); } if (value != null) { total += value.doubleValue(); } } V totalValue = instantiateValue(total); mColTotalMap.put(colKey, totalValue); } } if (CollectionUtil.hasValues(mColTotalMap)) { colTotal = mColTotalMap.get(inColKey); } return colTotal; } //-------------------------------------------------------------------------- public V getRowTotal(RK inRowKey) { V rowTotal = null; if (null == mRowTotalMap && CollectionUtil.hasValues(rowKeySet())) { Map map = new HashMap<>(rowKeySet().size()); for (RK rowKey : rowKeySet()) { double total = 0.0; for (CK colKey : colKeySet()) { V value = get(rowKey, colKey); if (null == mValueStringConstructor) { setValueStringConstructorFromValue(value); } if (value != null) { total += value.doubleValue(); } } V totalValue = instantiateValue(total); map.put(rowKey, totalValue); } mRowTotalMap = map; } if (CollectionUtil.hasValues(mRowTotalMap)) { rowTotal = mRowTotalMap.get(inRowKey); } return rowTotal; } //-------------------------------------------------------------------------- public V getGrandTotal() { if (null == mGrandTotal) { Map colTotalMap = getColTotalMap(); if (CollectionUtil.hasValues(colTotalMap)) { double total = 0.0; for (V value : colTotalMap.values()) { total += value.doubleValue(); } try { mGrandTotal = instantiateValue(total); } catch (Exception e) { throw new RuntimeException("Problem calculating totals!", e); } } } return mGrandTotal; } //-------------------------------------------------------------------------- /** * Calculates the percentage of the total column value represented by the specified cell. * * @param inRowKey the key of the selected row * @param inColKey the key of the selected column * @return the percentage of the total column value represented by the specified cell */ public Float getPercentOfCol(RK inRowKey, CK inColKey) { V value = get(inRowKey, inColKey); V colTotal = getColTotal(inColKey); return (value != null && colTotal != null && colTotal.floatValue() != 0.0f ? (value.floatValue() * 100f) / colTotal.floatValue() : null); } //-------------------------------------------------------------------------- /** * Calculates the percentage of the total row value represented by the specified cell. * * @param inRowKey the key of the selected row * @param inColKey the key of the selected column * @return the percentage of the total row value represented by the specified cell */ public Float getPercentOfRow(RK inRowKey, CK inColKey) { V value = get(inRowKey, inColKey); V rowTotal = getRowTotal(inRowKey); return (value != null && rowTotal != null && rowTotal.floatValue() != 0.0f ? (value.floatValue() * 100f) / rowTotal.floatValue() : null); } //-------------------------------------------------------------------------- /** * Calculates the percentage of the grand total (total of all cell values) represented by the specified cell. * * @param inRowKey the key of the selected row * @param inColKey the key of the selected column * @return the percentage of the grand total represented by the specified cell */ public Float getOverallPercent(RK inRowKey, CK inColKey) { V value = get(inRowKey, inColKey); V grandTotal = getGrandTotal(); return (value != null && grandTotal != null && grandTotal.floatValue() != 0.0f ? (value.floatValue() * 100f) / grandTotal.floatValue() : null); } //-------------------------------------------------------------------------- @Override public void put(RK inRowKey, CK inColKey, V inValue) { clearTotals(); super.put(inRowKey, inColKey, inValue); } //-------------------------------------------------------------------------- @Override public void putRow(RK inRowKey, Map inColMap) { clearTotals(); super.putRow(inRowKey, inColMap); } //-------------------------------------------------------------------------- @Override public void putCol(CK inColKey, Map inRowMap) { clearTotals(); super.putCol(inColKey, inRowMap); } //-------------------------------------------------------------------------- @Override public V remove(RK inRowKey, CK inColKey) { clearTotals(); return super.remove(inRowKey, inColKey); } //-------------------------------------------------------------------------- @Override public void clearRow(RK inRowKey) { clearTotals(); super.clearRow(inRowKey); } //-------------------------------------------------------------------------- @Override public void clearCol(CK inColKey) { clearTotals(); super.clearCol(inColKey); } //########################################################################## // PRIVATE METHODS //########################################################################## //-------------------------------------------------------------------------- private void clearTotals() { mRowTotalMap = null; mColTotalMap = null; mGrandTotal = null; } //-------------------------------------------------------------------------- private void setValueStringConstructorFromValue(V inValue) { try { mValueStringConstructor = inValue.getClass().getConstructor(String.class); } catch (Exception e) { throw new RuntimeException("Problem calculating totals!", e); } } //-------------------------------------------------------------------------- private V instantiateValue(double inValueAsDouble) { V newValue; try { String doubleString = inValueAsDouble + ""; // Prevent Integer constructor from barfing if (doubleString.endsWith(".0")) { doubleString = doubleString.substring(0, doubleString.length() - 2); } newValue = (V) mValueStringConstructor.newInstance(doubleString); } catch(Exception e) { throw new RuntimeException("Problem calculating totals!", e); } return newValue; } //-------------------------------------------------------------------------- private Map getColTotalMap() { if (null == mColTotalMap && CollectionUtil.hasValues(colKeySet())) { Map map = new HashMap<>(colKeySet().size()); for (CK colKey : colKeySet()) { double total = 0.0; for (RK rowKey : rowKeySet()) { V value = get(rowKey, colKey); if (null == mValueStringConstructor) { setValueStringConstructorFromValue(value); } if (value != null) { total += value.doubleValue(); } } V totalValue = instantiateValue(total); map.put(colKey, totalValue); } mColTotalMap = map; } return mColTotalMap; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy