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

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

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

import com.hfg.exception.DataParsingException;
import com.hfg.html.HTMLTag;
import com.hfg.html.Span;
import com.hfg.javascript.JsArray;
import com.hfg.javascript.JsCollection;
import com.hfg.javascript.JsObjMap;
import com.hfg.util.AttributeMgr;
import com.hfg.util.StringUtil;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

//------------------------------------------------------------------------------
/**
 Table containing sets of subject metadata.
 
@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 DataTable extends AbstractSparseMatrix { private String mName; private Set mFlags; private DataColumn mRowKeyCol; private AttributeMgr mAttributeMgr; //########################################################################## // CONSTRUCTORS //########################################################################## //-------------------------------------------------------------------------- public DataTable() { super(); } //-------------------------------------------------------------------------- public DataTable(int inInitialRowCapacity, int inInitialColCapacity) { super(inInitialRowCapacity, inInitialColCapacity); } //-------------------------------------------------------------------------- public DataTable(JsArray inJsonArray) { this(inJsonArray, null); } //-------------------------------------------------------------------------- /** * Constructor intended to take a JSON array of rows (as maps). * @param inJsonArray a JSON array object * @param inRowKeyCol an optional column to use as the row key. * If a value is not provided, the row number is used as the row key. */ public DataTable(JsArray inJsonArray, String inRowKeyCol) { this(); if (CollectionUtil.hasValues(inJsonArray)) { int rowCount = 0; for (JsCollection row : (Collection) (Object) inJsonArray) { if (row instanceof JsObjMap) { rowCount++; JsObjMap rowMap = (JsObjMap) row; String rowKey; if (inRowKeyCol != null) { rowKey = rowMap.getString(inRowKeyCol); } else { rowKey = rowCount + ""; } for (String key : rowMap.keySet()) { if (inRowKeyCol != null && inRowKeyCol.equals(key)) { continue; // Don't create a column for the row key } Object value = rowMap.get(key); if (value instanceof Comparable) { DataColumn col = getDataColumn(key); if (null == col) { col = new DataColumn(key); } put(rowKey, col, (Comparable) value); } } } } } } //--------------------------------------------------------------------------- public DataTable(List inParsedLines) throws IOException { Map colMap = new HashMap<>(10); boolean headerParsed = false; int rowIndex = 0; for (String[] fields : inParsedLines) { if (! headerParsed) { boolean hasData = StringUtil.isSet(fields[0]); if ((1 == fields.length && ! hasData) // Skip blank lines || (hasData && fields[0].startsWith("#"))) // Skip comment lines { continue; } for (int i = 0; i < fields.length; i++) { String field = fields[i]; if (field != null) { field = field.trim(); } else { field = "Col " + (i + 1); } DataColumn col = new DataColumn(field); colMap.put(i, col); } headerParsed = true; } else { rowIndex++; if (fields.length > colMap.size()) { throw new DataParsingException("Row " + rowIndex + " has more fields (" + fields.length + ") than the number of columns (" + colMap.size() + ")!"); } for (int i = 0; i < fields.length; i++) { String fieldString = fields[i]; Comparable field = null; if (fieldString != null) { fieldString = fieldString.trim(); if (StringUtil.isNumber(fieldString)) { try { if (fieldString.contains(".")) { field = Double.parseDouble(fieldString); } else if (fieldString.length() > 9) { field = Long.parseLong(fieldString); } else { field = Integer.parseInt(fieldString); } } catch (NumberFormatException e) { field = fieldString; } } else { field = fieldString; } } put(rowIndex + "", colMap.get(i), field); } } } } //########################################################################## // PUBLIC METHODS //########################################################################## //-------------------------------------------------------------------------- public String name() { return mName; } //-------------------------------------------------------------------------- public DataTable setName(String inValue) { mName = inValue; return this; } //-------------------------------------------------------------------------- public DataTable setRowKeyCol(DataColumn inValue) { mRowKeyCol = inValue; return this; } //-------------------------------------------------------------------------- public DataColumn getRowKeyCol() { return mRowKeyCol; } //-------------------------------------------------------------------------- public DataTable setFlag(String inValue) { if (null == mFlags) { mFlags = new HashSet<>(4); } mFlags.add(inValue); return this; } //-------------------------------------------------------------------------- public boolean hasFlag(String inValue) { return mFlags != null && mFlags.contains(inValue); } //-------------------------------------------------------------------------- public void clearFlags() { mFlags = null; } //-------------------------------------------------------------------------- public void clearFlag(String inValue) { if (mFlags != null) { mFlags.remove(inValue); } } //-------------------------------------------------------------------------- public DataTable add(DataTable inDataTable) { for (DataColumn dataColumn : inDataTable.getDataColumns()) { addDataSet(dataColumn, inDataTable.getDataSet(dataColumn)); } return this; } //-------------------------------------------------------------------------- public DataTable addDataSet(DataColumn inDataColumn, Map inDataMap) { for (String subjectId : inDataMap.keySet()) { put(subjectId, inDataColumn, inDataMap.get(subjectId)); } return this; } //-------------------------------------------------------------------------- @Override public DataRow getRow(String inRowKey) { Map colMap = super.getRow(inRowKey); return (colMap != null ? new DataRow(colMap) : null); } //-------------------------------------------------------------------------- public List getRows() { List rows = new ArrayList<>(rowKeySet().size()); for (String rowKey : rowKeySet()) { rows.add(getRow(rowKey)); } return rows; } //-------------------------------------------------------------------------- public String getFirstRowKey() /* Return the first Row Key Mainly used for single row DataTables to help find data*/ { Optional firstRowKey = rowKeySet().stream().findFirst(); return firstRowKey.isPresent() ? firstRowKey.get() : null; } //-------------------------------------------------------------------------- /* Make a new DataTable for the Rows that match the RowKey */ public DataTable getRows(String inRowKey) { DataRow dataRows = getRow(inRowKey); if (dataRows.size() == 0 ) { return null;} return makeDataTableFromDataRows(dataRows, inRowKey); } //-------------------------------------------------------------------------- public DataTable makeDataTableFromDataRows(DataRow inDataRow, String inRowKey) { int rowCount = 1; int colCount = inDataRow.getDataColumns().size(); DataTable dataTable = new DataTable(rowCount, colCount); dataTable.putRow(inRowKey, inDataRow); return dataTable; } //-------------------------------------------------------------------------- public DataTable makeDataTableMatchingColumnValues(DataColumn inDataColumn, V inQuery) /* Search a column within a DataTable, return a new DataTable with all the matching rows * Return Empty DataTable if no values are found * */ { List foundRowKeys = this.getRowKeysMatchingValues(inDataColumn, inQuery); int rowCount = foundRowKeys.size(); int colCount = colKeySet().size(); DataTable dataTable = new DataTable(rowCount, colCount); for (String rowKey: foundRowKeys ) { dataTable.putRow(rowKey, this.getRow(rowKey)); } return dataTable; } //-------------------------------------------------------------------------- public Map getDataSet(DataColumn inDataColumn) { return getCol(inDataColumn); } //-------------------------------------------------------------------------- public List getRowKeysMatchingValues(DataColumn inDataColumn, V inQuery ) /* Search a column for a value and return a unique list of all the RowsKeys found with the query value * */ { //Get a Map of all the column values: Key is RowKey Map colMap = getDataSet(inDataColumn); return colMap.entrySet() .stream() .filter(entry -> entry.getValue().equals(inQuery)) .map(entry -> (T) entry.getKey()) .distinct() .collect(Collectors.toList()); } //-------------------------------------------------------------------------- public void updateColumnTitle(DataColumn inColumn, String inNewTitle) { DataColumn newDataColumn = inColumn.clone().setTitle(inNewTitle); changeColKey(inColumn, newDataColumn); } //-------------------------------------------------------------------------- public Set getDataColumns() { return colKeySet(); } //-------------------------------------------------------------------------- public DataColumn getDataColumn(String inName) { DataColumn requestedCol = null; Set dataColumns = getDataColumns(); if (CollectionUtil.hasValues(dataColumns)) { for (DataColumn col : dataColumns) { if (col.getTitle().equalsIgnoreCase(inName)) { requestedCol = col; break; } } } return requestedCol; } //-------------------------------------------------------------------------- @Override public void removeCol(DataColumn inCol) { super.removeCol(inCol); } //-------------------------------------------------------------------------- @Override public Set rowKeySet() { return super.rowKeySet(); } //-------------------------------------------------------------------------- /** * Copies the row data for the specified columns into a new DataTable. * @param inColumns the columns to include * @return the DataTable copy */ public DataTable slice(DataColumn... inColumns) { ArrayList columns = new ArrayList<>(inColumns.length); for (DataColumn col : inColumns) { columns.add(col); } return slice(columns); } //-------------------------------------------------------------------------- /** * Copies the row data for the specified columns into a new DataTable. * @param inColumns the columns to include * @return the DataTable copy */ public DataTable slice(Collection inColumns) { DataTable slice = (DataTable) clone(); for (DataColumn col : getDataColumns()) { if (! inColumns.contains(col)) { slice.removeCol(col); } } return slice; } //-------------------------------------------------------------------------- /** * Copies the row data for columns other than the specified columns into a new DataTable. * @param inColumns the columns to exclude * @return the DataTable copy */ public DataTable inverseSlice(DataColumn... inColumns) { ArrayList columns = new ArrayList<>(inColumns.length); for (DataColumn col : inColumns) { columns.add(col); } return inverseSlice(columns); } //-------------------------------------------------------------------------- /** * Copies the row data for columns other than the specified columns into a new DataTable. * @param inColumns the columns to exclude * @return the DataTable copy */ public DataTable inverseSlice(Collection inColumns) { DataTable slice = (DataTable) clone(); for (DataColumn col : getDataColumns()) { if (inColumns.contains(col)) { slice.removeCol(col); } } return slice; } //-------------------------------------------------------------------------- /** Uses a formatting string (like "%.1f%%") specified via the DataColumn to render the object value for display. * @param inId subject key * @param inDataColumn the data column from which to retrieve the value * @return the String-formatted value */ public String getFormatted(String inId, DataColumn inDataColumn) { String formattedValue = ""; Object value = get(inId, inDataColumn); if (value != null) { if (inDataColumn.getFormatString() != null) { formattedValue = String.format(inDataColumn.getFormatString(), value); } else { formattedValue = value.toString(); } } return formattedValue; } //-------------------------------------------------------------------------- /** Uses a formatting string (like "%.1f%%") specified via the DataColumn to render the object value for display. * @param inId subject key * @param inDataColumn the data column from which to retrieve the value * @return the String-formatted value */ public HTMLTag getHTMLFormatted(String inId, DataColumn inDataColumn) { Object value = get(inId, inDataColumn); HTMLTag formattedValue; try { Method method = value.getClass().getMethod("toHTMLTag"); formattedValue = (HTMLTag) method.invoke(value); } catch (Exception e) { // Ignore exceptions. Just use the string value. formattedValue = new Span(getFormatted(inId, inDataColumn)); } return formattedValue; } //-------------------------------------------------------------------------- public void setAttribute(String inName, Object inValue) { getOrInitAttributeMgr().setAttribute(inName, inValue); } //-------------------------------------------------------------------------- public boolean hasAttributes() { return mAttributeMgr != null && mAttributeMgr.hasAttributes(); } //-------------------------------------------------------------------------- public boolean hasAttribute(String inName) { return mAttributeMgr != null && getOrInitAttributeMgr().hasAttribute(inName); } //-------------------------------------------------------------------------- public Object getAttribute(String inName) { return getOrInitAttributeMgr().getAttribute(inName); } //-------------------------------------------------------------------------- public Collection getAttributeNames() { return getOrInitAttributeMgr().getAttributeNames(); } //-------------------------------------------------------------------------- public void clearAttributes() { if (mAttributeMgr != null) { mAttributeMgr.clearAttributes(); } } //-------------------------------------------------------------------------- public Object removeAttribute(String inName) { Object attr = null; if (mAttributeMgr != null) { attr = getOrInitAttributeMgr().removeAttribute(inName); } return attr; } //-------------------------------------------------------------------------- public Boolean allColValuesMatch(DataColumn inCol) { List colValues = colValues(inCol); return colValues.stream().allMatch(i -> i.equals(colValues.get(0))); } //-------------------------------------------------------------------------- public List colValues(DataColumn inCol) { Map orderedDataSet = this.getDataSet(inCol); List colVals = (List) orderedDataSet.values(); return colVals; } //-------------------------------------------------------------------------- public Long countUnique(DataColumn inCol) { List colValues = colValues(inCol); return colValues.stream().distinct().count(); } //-------------------------------------------------------------------------- public List getUniqueValues(DataColumn inCol) /* Return a list of all values in column. Will attempt to Cast to the wanted Type when collecting data */ { Supplier> supplier = ArrayList::new; return colValues(inCol).stream() .map(s -> (T) s) .distinct() .collect(Collectors.toCollection(supplier)); } //########################################################################## // PRIVATE METHODS //########################################################################## //-------------------------------------------------------------------------- private AttributeMgr getOrInitAttributeMgr() { if (null == mAttributeMgr) { mAttributeMgr = new AttributeMgr(); } return mAttributeMgr; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy