com.hfg.util.collection.NumberMatrix Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com_hfg Show documentation
Show all versions of com_hfg Show documentation
com.hfg xml, html, svg, and bioinformatics utility library
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;
}
}