org.eclipse.collections.impl.multimap.AbstractMultimap Maven / Gradle / Ivy
/*
* Copyright (c) 2016 Goldman Sachs.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v. 1.0 which accompany this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.collections.impl.multimap;
import java.util.Map;
import org.eclipse.collections.api.RichIterable;
import org.eclipse.collections.api.bag.Bag;
import org.eclipse.collections.api.bag.MutableBag;
import org.eclipse.collections.api.block.function.Function;
import org.eclipse.collections.api.block.function.Function2;
import org.eclipse.collections.api.block.predicate.Predicate2;
import org.eclipse.collections.api.block.procedure.Procedure;
import org.eclipse.collections.api.block.procedure.Procedure2;
import org.eclipse.collections.api.map.MapIterable;
import org.eclipse.collections.api.multimap.Multimap;
import org.eclipse.collections.api.multimap.MutableMultimap;
import org.eclipse.collections.api.tuple.Pair;
import org.eclipse.collections.impl.UnmodifiableRichIterable;
import org.eclipse.collections.impl.block.factory.Functions;
import org.eclipse.collections.impl.factory.Bags;
import org.eclipse.collections.impl.tuple.Tuples;
public abstract class AbstractMultimap>
implements Multimap
{
protected abstract MapIterable getMap();
/**
* Creates the collection of values for a single key.
*
* Collections with weak, soft, or phantom references are not supported.
* Each call to {@code createCollection} should create a new instance.
*
* The returned collection class determines whether duplicate key-value
* pairs are allowed.
*
* @return an empty collection of values
*/
protected abstract C createCollection();
protected Function, C> createCollectionBlock()
{
return AbstractMultimap::createCollection;
}
// Query Operations
@Override
public boolean containsKey(Object key)
{
return this.getMap().containsKey(key);
}
@Override
public boolean containsValue(Object value)
{
return this.getMap().anySatisfy(collection -> collection.contains(value));
}
@Override
public boolean containsKeyAndValue(Object key, Object value)
{
C collection = this.getMap().get(key);
return collection != null && collection.contains(value);
}
// Views
@Override
public RichIterable keysView()
{
return this.getMap().keysView();
}
@Override
public RichIterable> multiValuesView()
{
return this.getMap().valuesView().collect(UnmodifiableRichIterable::of);
}
@Override
public Bag keyBag()
{
MutableBag bag = Bags.mutable.empty();
this.getMap().forEachKeyValue((key, value) -> bag.addOccurrences(key, value.size()));
return bag;
}
@Override
public RichIterable valuesView()
{
return this.getMap().valuesView().flatCollect(Functions.>identity());
}
@Override
public RichIterable>> keyMultiValuePairsView()
{
return this.getMap().keyValuesView().collect(pair -> Tuples.pair(pair.getOne(), UnmodifiableRichIterable.of(pair.getTwo())));
}
@Override
public RichIterable> keyValuePairsView()
{
return this.keyMultiValuePairsView().flatCollect(pair -> pair.getTwo().collect(new KeyValuePairFunction<>(pair.getOne())));
}
// Comparison and hashing
@Override
public boolean equals(Object object)
{
if (object == this)
{
return true;
}
if (object instanceof Multimap)
{
Multimap, ?> that = (Multimap, ?>) object;
return this.getMap().equals(that.toMap());
}
return false;
}
/**
* Returns the hash code for this multimap.
*
* The hash code of a multimap is defined as the hash code of the map view,
* as returned by {@link Multimap#toMap()}.
*
* @see Map#hashCode()
*/
@Override
public int hashCode()
{
return this.getMap().hashCode();
}
/**
* Returns a string representation of the multimap, generated by calling
* {@code toString} on the map returned by {@link Multimap#toMap()}.
*
* @return a string representation of the multimap
*/
@Override
public String toString()
{
return this.getMap().toString();
}
@Override
public boolean notEmpty()
{
return !this.isEmpty();
}
@Override
public void forEachValue(Procedure super V> procedure)
{
this.getMap().forEachValue(collection -> collection.forEach(procedure));
}
@Override
public void forEachKey(Procedure super K> procedure)
{
this.getMap().forEachKey(procedure);
}
@Override
public void forEachKeyValue(Procedure2 super K, ? super V> procedure)
{
Procedure2 innerProcedure = (value, key) -> procedure.value(key, value);
this.getMap().forEachKeyValue((key, collection) -> collection.forEachWith(innerProcedure, key));
}
@Override
public void forEachKeyMultiValues(Procedure2 super K, ? super Iterable> procedure)
{
this.getMap().forEachKeyValue(procedure);
}
@Override
public > R selectKeysValues(Predicate2 super K, ? super V> predicate, R target)
{
this.getMap().forEachKeyValue((key, collection) -> {
RichIterable selectedValues = collection.select(value -> predicate.accept(key, value));
target.putAll(key, selectedValues);
});
return target;
}
@Override
public > R rejectKeysValues(Predicate2 super K, ? super V> predicate, R target)
{
this.getMap().forEachKeyValue((key, collection) -> {
RichIterable selectedValues = collection.reject(value -> predicate.accept(key, value));
target.putAll(key, selectedValues);
});
return target;
}
@Override
public > R selectKeysMultiValues(Predicate2 super K, ? super Iterable> predicate, R target)
{
this.forEachKeyMultiValues((key, collection) -> {
if (predicate.accept(key, collection))
{
target.putAll(key, collection);
}
});
return target;
}
@Override
public > R rejectKeysMultiValues(Predicate2 super K, ? super Iterable> predicate, R target)
{
this.forEachKeyMultiValues((key, collection) -> {
if (!predicate.accept(key, collection))
{
target.putAll(key, collection);
}
});
return target;
}
private static final class KeyValuePairFunction implements Function>
{
private static final long serialVersionUID = 1L;
private final K key;
private KeyValuePairFunction(K key)
{
this.key = key;
}
@Override
public Pair valueOf(V value)
{
return Tuples.pair(this.key, value);
}
}
@Override
public > R collectKeysValues(Function2 super K, ? super V, Pair> function, R target)
{
this.getMap().forEachKeyValue((key, collection) -> collection.each(value -> target.add(function.value(key, value))));
return target;
}
@Override
public > R collectValues(Function super V, ? extends V2> function, R target)
{
this.getMap().forEachKeyValue((key, collection) -> target.putAll(key, collection.collect(function)));
return target;
}
}