org.datacleaner.result.Crosstab Maven / Gradle / Ivy
/**
* DataCleaner (community edition)
* Copyright (C) 2014 Free Software Foundation, Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.datacleaner.result;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Supplier;
import org.apache.metamodel.util.SerializableRef;
import org.datacleaner.util.ReflectionUtils;
public final class Crosstab implements Serializable {
private static final long serialVersionUID = 1L;
private final List dimensions;
private final Map values = new HashMap<>();
private final Class valueClass;
private final Map> resultProducers = new HashMap<>();
public Crosstab(final Class valueClass, final CrosstabDimension... dimensions) {
this.valueClass = valueClass;
this.dimensions = Arrays.asList(dimensions);
}
public Crosstab(final Class valueClass, final Collection dimensions) {
this.valueClass = valueClass;
this.dimensions = new ArrayList<>(dimensions);
}
public Crosstab(final Class valueClass, final String... dimensionNames) {
this.valueClass = valueClass;
dimensions = new ArrayList<>();
for (final String name : dimensionNames) {
dimensions.add(new CrosstabDimension(name));
}
}
public Class getValueClass() {
return valueClass;
}
@SuppressWarnings("unchecked")
public Crosstab castValueClass(final Class valueClass) {
if (ReflectionUtils.is(this.valueClass, valueClass)) {
return (Crosstab) this;
}
throw new IllegalArgumentException("Unable to cast [" + this.valueClass + "] to [" + valueClass + "]");
}
public List getDimensions() {
return Collections.unmodifiableList(dimensions);
}
private String getKey(final String[] categories) throws IllegalArgumentException, NullPointerException {
if (categories.length != dimensions.size()) {
throw new IllegalArgumentException(
"Not all dimensions have been specified (differences in size of parameter and Crosstab's dimensions)");
}
for (int i = 0; i < categories.length; i++) {
if (categories[i] == null) {
final CrosstabDimension dimension = dimensions.get(i);
throw new NullPointerException(
"Not all dimensions have been specified ('" + dimension.getName() + "' is null)");
}
}
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < categories.length; i++) {
final CrosstabDimension dimension = dimensions.get(i);
final String category = categories[i];
if (!dimension.containsCategory(category)) {
throw new IllegalArgumentException(
"Unknown category [" + category + "] for dimension [" + dimension.getName() + "]");
}
if (i != 0) {
sb.append('^');
}
sb.append(category);
}
return sb.toString();
}
public CrosstabNavigator navigate() {
return new CrosstabNavigator<>(this);
}
protected E getValue(final String[] categories) throws IllegalArgumentException, NullPointerException {
final String key = getKey(categories);
return values.get(key);
}
public CrosstabNavigator where(final String dimension, final String isCategory) {
return navigate().where(dimension, isCategory);
}
public CrosstabNavigator where(final CrosstabDimension dimension, final String isCategory) {
return navigate().where(dimension, isCategory);
}
protected void putValue(final E value, final String[] categories)
throws IllegalArgumentException, NullPointerException {
if (value != null) {
if (!ReflectionUtils.is(value.getClass(), valueClass)) {
throw new IllegalArgumentException("Cannot put value [" + value + "] of type [" + value.getClass()
+ "] when Crosstab.valueClass is [" + valueClass + "]");
}
}
final String key = getKey(categories);
values.put(key, value);
}
public int getDimensionCount() {
return dimensions.size();
}
public String[] getDimensionNames() {
final int size = dimensions.size();
final String[] result = new String[size];
for (int i = 0; i < size; i++) {
result[i] = dimensions.get(i).getName();
}
return result;
}
public int getDimensionIndex(final CrosstabDimension dimension) {
if (dimension != null) {
final int size = dimensions.size();
for (int i = 0; i < size; i++) {
if (dimension.equals(dimensions.get(i))) {
return i;
}
}
}
throw new IllegalArgumentException("No such dimension: " + dimension);
}
public int getDimensionIndex(final String dimensionName) {
if (dimensionName != null) {
final int size = dimensions.size();
for (int i = 0; i < size; i++) {
if (dimensionName.equals(dimensions.get(i).getName())) {
return i;
}
}
}
throw new IllegalArgumentException("No such dimension: " + dimensionName);
}
public CrosstabDimension getDimension(final int index) {
return dimensions.get(index);
}
public CrosstabDimension getDimension(final String dimensionName) {
return getDimension(getDimensionIndex(dimensionName));
}
protected void attachResultProducer(final ResultProducer resultProducer, final String[] categories)
throws IllegalArgumentException, NullPointerException {
final String key = getKey(categories);
if (resultProducer == null) {
resultProducers.remove(key);
} else {
final Supplier resultProducerRef = new SerializableRef<>(resultProducer);
resultProducers.put(key, resultProducerRef);
}
}
protected ResultProducer explore(final String[] categories) {
final String key = getKey(categories);
final Supplier resultProducerRef = resultProducers.get(key);
if (resultProducerRef == null) {
return null;
}
return resultProducerRef.get();
}
@Override
public String toString() {
return toString(8);
}
/**
* Returns a string representation with a maximum restraint on the amount of
* crosstab entries to include.
*
* @param maxEntries
* the maximum amount of crosstab entries to include, or negative
* if all entries should be included.
* @return
*/
public String toString(int maxEntries) {
final StringBuilder sb = new StringBuilder("Crosstab:");
final Set keySet = new TreeSet<>(values.keySet());
for (final String key : keySet) {
if (maxEntries == 0) {
break;
}
sb.append('\n');
sb.append(key.replaceAll("\\^", ","));
sb.append(": ");
final E value = values.get(key);
sb.append(value);
maxEntries--;
}
return sb.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy