/* * This file is part of JGAP. * * JGAP offers a dual license model containing the LGPL as well as the MPL. * * For licensing information please see the file license.txt included with JGAP * or have a look at the top of class org.jgap.Chromosome which representatively * includes the JGAP license policy applicable for any file delivered with JGAP. */ package org.jgap.audit; import java.io.*; import java.util.*; import org.jgap.util.*; /** * A collection of (row, column) tupels * * @author Klaus Meffert * @since 2.3 */ public class KeyedValues2D implements ICloneable, Serializable { /** String containing the CVS revision. Read out via reflection!*/ private static final String CVS_REVISION = "$Revision: 1.7 $"; /** The row keys */ private List m_rowKeys; /** The column keys */ private List m_columnKeys; /** The row data */ private List m_rows; /** Should row keys be sorted by their comparable order? */ private boolean m_sortRowKeys; /** * Constructor setting behavior: non-sorted keys * * @author Klaus Meffert * @since 2.3 */ public KeyedValues2D() { this(false); } /** * Constructor. * * @param a_sortRowKeys true: row keys should be sorted * * @author Klaus Meffert * @since 2.3 */ public KeyedValues2D(final boolean a_sortRowKeys) { m_rowKeys = Collections.synchronizedList(new ArrayList()); m_columnKeys = Collections.synchronizedList(new ArrayList()); m_rows = Collections.synchronizedList(new ArrayList()); m_sortRowKeys = a_sortRowKeys; } /** * @return the number of rows * * @author Klaus Meffert * @since 2.3 */ public int getRowCount() { return m_rowKeys.size(); } /** * @return the number of columns * * @author Klaus Meffert * @since 2.3 */ public int getColumnCount() { return m_columnKeys.size(); } /** * Returns the value for a given row and column * * @param a_row the row index * @param a_column the column index * * @return value at given row and column * * @author Klaus Meffert * @since 2.3 */ public Number getValue(final int a_row, final int a_column) { Number result = null; final KeyedValues rowData = (KeyedValues) m_rows.get(a_row); final Comparable columnKey = (Comparable) m_columnKeys.get(a_column); if (columnKey != null) { result = rowData.getValue(columnKey); } return result; } /** * @param a_row the row index, starting at 0 * * @return key for the given row * * @author Klaus Meffert * @since 2.3 */ public Comparable getRowKey(final int a_row) { return (Comparable) m_rowKeys.get(a_row); } /** * @param a_key the row key * * @return row index for the given key * * @author Klaus Meffert * @since 2.3 */ public int getRowIndex(final Comparable a_key) { if (m_sortRowKeys) { return Collections.binarySearch(m_rowKeys, a_key); } else { return m_rowKeys.indexOf(a_key); } } /** * @return row keys * * @author Klaus Meffert * @since 2.3 */ public List getRowKeys() { return Collections.unmodifiableList(m_rowKeys); } /** * @param a_column the column * * @return key for the given column * * @author Klaus Meffert * @since 2.3 */ public Comparable getColumnKey(final int a_column) { return (Comparable) m_columnKeys.get(a_column); } /** * @return the column keys * * @author Klaus Meffert * @since 2.3 */ public List getColumnKeys() { return Collections.unmodifiableList(m_columnKeys); } /** * @param a_rowKey the row key * @param a_columnKey the column key * * @return value for the given row and column keys * * @author Klaus Meffert * @since 2.3 */ public Number getValue(final Comparable a_rowKey, final Comparable a_columnKey) { Number result; final int row = getRowIndex(a_rowKey); if (row >= 0) { final KeyedValues rowData = (KeyedValues) m_rows.get(row); result = rowData.getValue(a_columnKey); } else { result = null; } return result; } /** * Sets a value. * * @param a_value the value * @param a_rowKey the row key * @param a_columnKey the column key * * @author Klaus Meffert * @since 2.3 */ public void setValue(final Number a_value, final Comparable a_rowKey, final Comparable a_columnKey) { final KeyedValues row; int rowIndex = getRowIndex(a_rowKey); if (rowIndex >= 0) { row = (KeyedValues) m_rows.get(rowIndex); } else { row = new KeyedValues(); if (m_sortRowKeys) { rowIndex = -rowIndex - 1; m_rowKeys.add(rowIndex, a_rowKey); m_rows.add(rowIndex, row); } else { m_rowKeys.add(a_rowKey); m_rows.add(row); } } row.setValue(a_columnKey, a_value); final int columnIndex = m_columnKeys.indexOf(a_columnKey); if (columnIndex < 0) { m_columnKeys.add(a_columnKey); } } /** * Tests if this object is equal to another * * @param a_object other object. * * @return true: this object is equal to the other one * * @author Klaus Meffert * @since 2.3 */ public boolean equals(final Object a_object) { if (a_object == null) { return false; } if (a_object == this) { return true; } if (! (a_object instanceof KeyedValues2D)) { return false; } final KeyedValues2D kv2D = (KeyedValues2D) a_object; if (!getRowKeys().equals(kv2D.getRowKeys())) { return false; } if (!getColumnKeys().equals(kv2D.getColumnKeys())) { return false; } int rowCount = getRowCount(); int colCount = getColumnCount(); for (int r = 0; r < rowCount; r++) { for (int c = 0; c < colCount; c++) { final Number v1 = getValue(r, c); final Number v2 = kv2D.getValue(r, c); if (v1 == null) { if (v2 != null) { return false; } } else { if (!v1.equals(v2)) { return false; } } } } return true; } /** * @return hash code of the instance * * @author Klaus Meffert * @since 2.3 */ public int hashCode() { int result; result = m_rowKeys.hashCode(); result = 29 * result + m_columnKeys.hashCode(); result = 31 * result + m_rows.hashCode(); return result; } /** * @return clone of the current instance * * @author Klaus Meffert * @since 2.3 */ public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException cex) { throw new CloneException(cex); } } }