edu.isi.nlp.collections.ImmutableSetMultitable Maven / Gradle / Ivy
The newest version!
package edu.isi.nlp.collections;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Multimap;
import com.google.common.collect.Table;
import edu.isi.nlp.IsiNlpImmutable;
import java.util.Collection;
import java.util.Set;
import javax.annotation.Nullable;
import org.immutables.value.Value;
/**
* A Multitable that cannot hold duplicate key-key-value triples. Adding a key-key-value triple that
* is already in the multitable has no effect.
*
* @see Multitable
* @see ImmutableMultitable
* @author Chester Palen-Michel, Constantine Lignos, Ryan Gabbard
*/
public final class ImmutableSetMultitable extends ImmutableMultitable
implements SetMultitable {
private final ImmutableTable> table;
private final int size;
private final ImmutableMap> rowMap;
private final ImmutableMap> columnMap;
private final ImmutableSet> cellSet;
private final ImmutableMultiset allValues;
private ImmutableSetMultitable(
final ImmutableTable> table,
final int size,
ImmutableSet rowIterationOrder,
ImmutableSet columnIterationOrder) {
this.table = checkNotNull(table);
this.size = size; // all available construction methods ensure size matches table
// This is more than we generally want in constructor, but we are only caching to return views.
// cache rowMap
final ImmutableMap.Builder> rowMapBuilder = ImmutableMap.builder();
for (final R rowKey : rowIterationOrder) {
final ImmutableSetMultimap.Builder colMultiBuilder = ImmutableSetMultimap.builder();
for (final C columnKey : columnIterationOrder) {
final Collection value = table.get(rowKey, columnKey);
if (value != null) {
colMultiBuilder.putAll(columnKey, value);
}
}
rowMapBuilder.put(rowKey, colMultiBuilder.build());
}
this.rowMap = rowMapBuilder.build();
// cache columnMap
final ImmutableMap.Builder> columnMapBuilder = ImmutableMap.builder();
for (final C columnKey : columnIterationOrder) {
final ImmutableSetMultimap.Builder rowMultiBuilder = ImmutableSetMultimap.builder();
for (final R rowKey : rowIterationOrder) {
final Collection value = table.get(rowKey, columnKey);
if (value != null) {
rowMultiBuilder.putAll(rowKey, value);
}
}
columnMapBuilder.put(columnKey, rowMultiBuilder.build());
}
this.columnMap = columnMapBuilder.build();
// cache cellSet and allValues
final ImmutableMultiset.Builder valuesBuilder = ImmutableMultiset.builder();
final ImmutableSet.Builder> cellSetBuilder = ImmutableSet.builder();
for (final R rowKey : rowIterationOrder) {
for (final C columnKey : columnIterationOrder) {
final Collection values = table.get(rowKey, columnKey);
if (values != null) {
final ImmutableSetMulticell.Builder multicellBuilder =
new ImmutableSetMultitable.SetMulticell.Builder()
.rowKey(rowKey)
.columnKey(columnKey);
multicellBuilder.values(values);
valuesBuilder.addAll(values);
cellSetBuilder.add(multicellBuilder.build());
}
}
}
this.cellSet = cellSetBuilder.build();
this.allValues = valuesBuilder.build();
}
@Override
protected Table> table() {
return table;
}
/**
* Returns the set of values corresponding to the given row and column keys, or an empty set if no
* such mapping exists. This exists in addition to {@code get} as a type-safe way of returning a
* set of values at a specified cell.
*
* @param rowKey key of row to search for
* @param columnKey key of column to search for
*/
@Override
@SuppressWarnings("unchecked")
public ImmutableSet getAsSet(@Nullable final Object rowKey, @Nullable final Object columnKey) {
final Collection ret = table.get(rowKey, columnKey);
if (ret != null) {
return (ImmutableSet) ret; // cast guaranteed to succeed because table made of sets
} else {
return ImmutableSet.of();
}
}
@Override
public ImmutableMap> rowMap() {
return rowMap;
}
@Override
public ImmutableMap> columnMap() {
return columnMap;
}
@Override
public Set> cellSet() {
return cellSet;
}
/**
* Returns {@code true} if the table contains a mapping with the specified value. Runs in O(1)
* time.
*
* @param value value to search for
*/
@Override
public boolean containsValue(@Nullable final Object value) {
return allValues.contains(value);
}
@Override
public Collection get(@Nullable final Object rowKey, @Nullable final Object columnKey) {
final Collection ret = table.get(rowKey, columnKey);
if (ret != null) {
return ret;
} else {
return ImmutableSet.of();
}
}
@Override
public ImmutableMultiset values() {
return allValues;
}
@Override
public int size() {
return size;
}
public static ImmutableSetMultitable.Builder builder() {
return new Builder<>();
}
public static class Builder implements ImmutableMultitable.Builder {
// we use the two tables because we both need to maintain insertion order and
// be able to do lookups during building. The values of both sets are
// the same identical objects
private final HashBasedTable> tableWeCanLookUpIn =
HashBasedTable.create();
private final ImmutableSet.Builder> rowInsertionOrder =
ImmutableSet.builder();
private Builder() {}
private ImmutableSet.Builder setForKey(final R rowKey, final C columnKey) {
ImmutableSet.Builder values = tableWeCanLookUpIn.get(rowKey, columnKey);
if (values == null) {
values = ImmutableSet.builder();
tableWeCanLookUpIn.put(rowKey, columnKey, values);
rowInsertionOrder.add(RowKeyColumnKeyPair.of(rowKey, columnKey));
}
return values;
}
@Override
public Builder put(R rowKey, C columnKey, V value) {
setForKey(rowKey, columnKey).add(value);
return this;
}
@Override
public Builder putAll(
final R rowKey, final C columnKey, final Iterable extends V> values) {
setForKey(rowKey, columnKey).addAll(values);
return this;
}
public ImmutableSetMultitable build() {
final ImmutableTable.Builder> immutableTable = ImmutableTable.builder();
int size = 0;
ImmutableSet.Builder rowIterationBuilder = ImmutableSet.builder();
ImmutableSet.Builder columnIterationBuilder = ImmutableSet.builder();
for (final RowKeyColumnKeyPair rowKeyColKey : rowInsertionOrder.build()) {
final ImmutableSet valuesForPair =
tableWeCanLookUpIn.get(rowKeyColKey.row(), rowKeyColKey.column()).build();
size += valuesForPair.size();
immutableTable.put(rowKeyColKey.row(), rowKeyColKey.column(), valuesForPair);
rowIterationBuilder.add(rowKeyColKey.row());
columnIterationBuilder.add(rowKeyColKey.column());
}
return new ImmutableSetMultitable<>(
immutableTable.build(),
size,
rowIterationBuilder.build(),
columnIterationBuilder.build());
}
}
@IsiNlpImmutable
@Value.Immutable
abstract static class SetMulticell implements SetMultitable.SetMulticell {
@Override
public abstract R getRowKey();
@Override
public abstract C getColumnKey();
@Override
public abstract Set getValues();
public static class Builder extends ImmutableSetMulticell.Builder {}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy