no.ssb.jsonstat.v2.support.DatasetTableView Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of json-stat-java Show documentation
Show all versions of json-stat-java Show documentation
Json stat implementation in Java
The newest version!
package no.ssb.jsonstat.v2.support;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import com.google.common.collect.Tables;
import com.google.common.collect.UnmodifiableIterator;
import no.ssb.jsonstat.v2.Dataset;
import no.ssb.jsonstat.v2.Dimension;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* An implementation of a {@link Table} that uses a {@link Dataset}
* as data source.
*/
public class DatasetTableView implements Table, List, Number> {
private final Dataset source;
private final ImmutableSet rows;
private final ImmutableSet columns;
private final ImmutableMap factors;
private final ImmutableMap> dimensions;
private final Set> rowIndex;
private final Set> columnIndex;
private final Integer size;
public DatasetTableView(Dataset dataset, Set rows, Set colums) {
this.source = checkNotNull(dataset, "dataset cannot be null");
checkArgument(
source.getDimension().keySet().equals(Sets.union(rows, colums)),
"invalid row or column dimension names"
);
this.rows = ImmutableSet.copyOf(rows);
this.columns = ImmutableSet.copyOf(colums);
checkArgument(dataset.getId().size() == dataset.getSize().size());
checkArgument(dataset.getId().size() >= 2, "need at least two dimensions to " +
"represent as a table");
ImmutableMap.Builder factors = ImmutableMap.builder();
UnmodifiableIterator sizeIterator = dataset.getSize().reverse().iterator();
UnmodifiableIterator idIterator = dataset.getId().asList().reverse().iterator();
factors.put(idIterator.next(), 1);
Integer size = 1;
while (sizeIterator.hasNext() && idIterator.hasNext()) {
size *= sizeIterator.next();
factors.put(idIterator.next(), size);
}
this.factors = factors.build();
ImmutableMap.Builder> dimensions = ImmutableMap.builder();
for (Map.Entry dimensionEntry : source.getDimension().entrySet()) {
String dimensionName = dimensionEntry.getKey();
ImmutableList dimensionIndex = dimensionEntry.getValue().getCategory().getIndex().asList();
dimensions.put(dimensionName, dimensionIndex);
}
this.dimensions = dimensions.build();
this.rowIndex = computeIndex(rows);
this.columnIndex = computeIndex(colums);
this.size = source.getSize().stream().reduce(1, (a, b) -> a * b);
}
/**
* Delegates to {@link Map#containsKey}. Returns {@code false} on {@code
* ClassCastException} and {@code NullPointerException}.
*/
static boolean safeContainsKey(Map, ?> map, Object key) {
checkNotNull(map);
try {
return map.containsKey(key);
} catch (ClassCastException | NullPointerException e) {
return false;
}
}
/**
* Delegates to {@link Map#get}. Returns {@code null} on {@code
* ClassCastException} and {@code NullPointerException}.
*/
static V safeGet(Map, V> map, Object key) {
checkNotNull(map);
try {
return map.get(key);
} catch (ClassCastException | NullPointerException e) {
return null;
}
}
private Set> computeIndex(Set dimensions) {
List> rowDimensions = Lists.newArrayList();
for (String row : dimensions) {
rowDimensions.add(ImmutableSet.copyOf(this.dimensions.get(row)));
}
return Sets.cartesianProduct(rowDimensions);
}
@Override
public boolean containsRow(Object rowKey) {
return safeContainsKey(rowMap(), rowKey);
}
@Override
public boolean containsColumn(Object columnKey) {
return safeContainsKey(columnMap(), columnKey);
}
@Override
public Set> rowKeySet() {
return rowIndex;
}
@Override
public Set> columnKeySet() {
return columnIndex;
}
@Override
public boolean containsValue(Object value) {
for (Map, Number> row : rowMap().values()) {
if (row.containsValue(value)) {
return true;
}
}
return false;
}
@Override
public boolean contains(Object rowKey, Object columnKey) {
return get(rowKey, columnKey) != null;
}
@Override
public Number get(Object rowKey, Object columnKey) {
try {
List rowList = ((List) rowKey);
List columnList = ((List) columnKey);
ImmutableList rows = this.rows.asList();
int index = 0;
for (int i = 0; i < rows.size(); i++) {
String key = rowList.get(i);
String row = rows.get(i);
index += dimensions.get(row).indexOf(key) * factors.get(row);
}
ImmutableList columns = this.columns.asList();
for (int i = 0; i < columns.size(); i++) {
String key = columnList.get(i);
String column = columns.get(i);
index += dimensions.get(column).indexOf(key) * factors.get(column);
}
return source.getValue().get(index);
} catch (ClassCastException e) {
return null;
}
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public int size() {
return size;
}
@Override
public Map, Number> row(List rowKey) {
return new AbstractMap, Number>() {
@Override
public Set, Number>> entrySet() {
return new AbstractSet, Number>>() {
@Override
public Iterator, Number>> iterator() {
return Iterators.transform(
DatasetTableView.this.columnKeySet().iterator(),
columnKey -> {
return new SimpleEntry<>(columnKey, DatasetTableView.this.get(rowKey, columnKey));
}
);
}
@Override
public int size() {
return DatasetTableView.this.columnKeySet().size();
}
};
}
};
}
@Override
public Map, Number> column(List columnKey) {
return new AbstractMap, Number>() {
@Override
public Set, Number>> entrySet() {
return new AbstractSet, Number>>() {
@Override
public Iterator, Number>> iterator() {
return Iterators.transform(
DatasetTableView.this.rowKeySet().iterator(),
rowKey -> {
return new SimpleEntry<>(rowKey, DatasetTableView.this.get(rowKey, columnKey));
}
);
}
@Override
public int size() {
return DatasetTableView.this.rowKeySet().size();
}
};
}
};
}
@Override
public Set, List, Number>> cellSet() {
Set>> lists = Sets.cartesianProduct(rowKeySet(), columnKeySet());
return lists.stream().map(dimensions -> {
return Tables.immutableCell(dimensions.get(0), dimensions.get(1), get(dimensions.get(0), dimensions.get(1)));
}).collect(Collectors.toSet());
}
@Override
public Collection values() {
return source.getRows();
}
@Override
public Map, Map, Number>> rowMap() {
return new AbstractMap, Map, Number>>() {
@Override
public Set, Map, Number>>> entrySet() {
return new AbstractSet, Map, Number>>>() {
@Override
public Iterator, Map, Number>>> iterator() {
return Iterators.transform(
rowKeySet().iterator(),
rowKey -> {
return new SimpleEntry<>(
rowKey, DatasetTableView.this.row(rowKey)
);
});
}
@Override
public int size() {
return rowKeySet().size();
}
};
}
};
}
@Override
public Map, Map, Number>> columnMap() {
return new AbstractMap, Map, Number>>() {
@Override
public Set, Map, Number>>> entrySet() {
return new AbstractSet, Map, Number>>>() {
@Override
public Iterator, Map, Number>>> iterator() {
return Iterators.transform(
columnKeySet().iterator(),
columnKey -> {
return new SimpleEntry<>(
columnKey, DatasetTableView.this.column(columnKey)
);
});
}
@Override
public int size() {
return columnKeySet().size();
}
};
}
};
}
/**
* Guaranteed to throw an exception and leave the table unmodified.
*
* @throws UnsupportedOperationException always
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public final void clear() {
throw new UnsupportedOperationException();
}
/**
* Guaranteed to throw an exception and leave the table unmodified.
*
* @throws UnsupportedOperationException always
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public final Number put(List rowKey, List columnKey, Number value) {
throw new UnsupportedOperationException();
}
/**
* Guaranteed to throw an exception and leave the table unmodified.
*
* @throws UnsupportedOperationException always
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public final void putAll(Table extends List, ? extends List, ? extends Number> table) {
throw new UnsupportedOperationException();
}
/**
* Guaranteed to throw an exception and leave the table unmodified.
*
* @throws UnsupportedOperationException always
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public final Number remove(Object rowKey, Object columnKey) {
throw new UnsupportedOperationException();
}
}
|