/* * Copyright 2014 Goldman Sachs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gs.collections.api.multimap; import java.util.Collection; import com.gs.collections.api.RichIterable; import com.gs.collections.api.bag.Bag; import com.gs.collections.api.block.function.Function; import com.gs.collections.api.block.function.Function0; import com.gs.collections.api.block.function.Function2; import com.gs.collections.api.block.predicate.Predicate2; import com.gs.collections.api.block.procedure.Procedure; import com.gs.collections.api.block.procedure.Procedure2; import com.gs.collections.api.map.MutableMap; import com.gs.collections.api.tuple.Pair; /** * This collection is a type of {@code Map} that can associate multiple values for keys. * <p> * <p>Unlike {@code Map} however, this interface is read-only so the results of access methods such as {@link * #get(Object)} return a view onto the values associated with that key. The {@link MutableMultimap} subinterface * provides methods to mutate the collection. * <p> * <p>The advantages to using this container over a {@code Map<K, Collection<V>>} is that all of the handling of the * value collection can be done automatically. It also allows implementations to further specialize in how duplicate * values will be handled. Value collections with list semantics would allow duplicate values for a key, while those * implementing set semantics would not. The value collections can never be empty. * <p> * <p>Internal iteration methods for keys and values (singly - {@link #forEachKey(Procedure)}, {@link * #forEachValue(Procedure)}, and together - {@link #forEachKeyValue(Procedure2)}), {@link #forEachKeyMultiValues(Procedure2)}) are provided to allow flexible * browsing of the collection's contents. Similarly, views also are provided for keys ({@link #keysView()}), values * ({@link #valuesView()}) and the combination thereof ({@link #keyValuePairsView()}, {@link * #keyMultiValuePairsView()}). * <p> * * @param <K> the type of keys used * @param <V> the type of mapped values * @since 1.0 */ @SuppressWarnings("JavaDoc") public interface Multimap<K, V> { /** * Creates a new instance of the same implementation type, using the default capacity and growth parameters. */ Multimap<K, V> newEmpty(); /** * Returns {@code true} if there are no entries. */ boolean isEmpty(); /** * Returns {@code true} if there is at least one entry. */ boolean notEmpty(); /** * Calls the procedure with each <em>value</em>. * <p> * Given a Multimap with the contents: * <p> * {@code { "key1" : ["val1", "val2", "val2"], "key2" : ["val3"] }} * <p> * The given procedure would be invoked with the parameters: * <p> * {@code [ "val1", "val2", "val2", "val3" ]} */ void forEachValue(Procedure<? super V> procedure); /** * Calls the {@code procedure} with each <em>key</em>. * <p> * Given a Multimap with the contents: * <p> * {@code { "key1" : ["val1", "val2", "val2"], "key2" : ["val3"] }} * <p> * The given procedure would be invoked with the parameters: * <p> * {@code [ "key1", "key2" ]} */ void forEachKey(Procedure<? super K> procedure); /** * Calls the {@code procedure} with each <em>key-value</em> pair. * <p> * Given a Multimap with the contents: * <p> * {@code { "key1" : ["val1", "val2", "val2"], "key2" : ["val3"] }} * <p> * The given procedure would be invoked with the parameters: * <p> * {@code [ ["key1", "val1"], ["key1", "val2"], ["key1", "val2"], ["key2", "val3"] ]} */ void forEachKeyValue(Procedure2<K, V> procedure); /** * Calls the {@code procedure} with each <em>key-Iterable[value]</em>. * <p> * Given a Multimap with the contents: * <p> * {@code { "key1" : ["val1", "val2", "val2"], "key2" : ["val3"] }} * <p> * The given procedure would be invoked with the parameters: * <p> * {@code [ ["key1", {@link RichIterable["val1", "val2", "val2"]}], ["key2", {@link RichIterable["val3"]}] ]} * * @since 6.0 */ void forEachKeyMultiValues(Procedure2<K, ? super Iterable<V>> procedure); /** * Returns the number of key-value entry pairs. * <p> * This method is implemented with O(1) (constant-time) performance. */ int size(); /** * Returns the number of distinct keys. */ int sizeDistinct(); /** * Returns {@code true} if any values are mapped to the specified key. * * @param key the key to search for */ boolean containsKey(Object key); /** * Returns {@code true} if any key is mapped to the specified value. * * @param value the value to search for */ boolean containsValue(Object value); /** * Returns {@code true} if the specified key-value pair is mapped. * * @param key the key to search for * @param value the value to search for */ boolean containsKeyAndValue(Object key, Object value); /** * Returns a view of all values associated with the given key. * <p> * If the given key does not exist, an empty {@link RichIterable} is returned. * * @param key the key to search for */ RichIterable<V> get(K key); /** * Returns a lazy view of the unique keys. */ RichIterable<K> keysView(); /** * Returns a {@link Bag} of keys with the count corresponding to the number of mapped values. */ Bag<K> keyBag(); /** * Returns an unmodifiable view of all of the values mapped to each key. */ RichIterable<RichIterable<V>> multiValuesView(); /** * Returns a lazy flattened view of all the values. */ RichIterable<V> valuesView(); /** * Returns a lazy view of the pair of a key and and a lazy view of the values mapped to that key. */ RichIterable<Pair<K, RichIterable<V>>> keyMultiValuePairsView(); /** * Returns a lazy view of all of the key/value pairs. */ RichIterable<Pair<K, V>> keyValuePairsView(); /** * Returns a new {@link MutableMap} of keys from this Multimap to the mapped values as a {@link RichIterable}. */ MutableMap<K, RichIterable<V>> toMap(); /** * Returns a new {@link MutableMap} of keys from this Multimap to the mapped values as a {@link RichIterable}. * * @param collectionFactory used to create the collections that hold the values and affects the return type */ <R extends Collection<V>> MutableMap<K, R> toMap(Function0<R> collectionFactory); /** * Compares the specified object with this Multimap for equality. * <p> * Two Multimaps are equal when their map views (as returned by {@link #toMap}) are also equal. * <p> * In general, two Multimaps with identical key-value mappings may or may not be equal, depending on the type of * the collections holding the values. If the backing collections are Sets, then two instances with the same * key-value mappings are equal, but if the backing collections are Lists, equality depends on the ordering of the * values for each key. * <p> * Any two empty Multimaps are equal, because they both have empty {@link #toMap} views. */ boolean equals(Object obj); /** * Returns the hash code for this Multimap. * <p> * The hash code of a Multimap is defined as the hash code of the map view, as returned by {@link #toMap}. */ int hashCode(); /** * Returns a mutable <em>copy</em> of this Multimap. */ MutableMultimap<K, V> toMutable(); /** * Returns an immutable copy of this Multimap <em>if it is not already immutable</em>. If the Multimap is immutable, * it will return itself. * <p> * The returned Multimap will be {@code Serializable} if this Multimap is {@code Serializable}. */ ImmutableMultimap<K, V> toImmutable(); /** * Given a Multimap from Domain -> Range return a multimap from Range -> Domain. * * @since 6.0 */ Multimap<V, K> flip(); /** * Returns all elements of the source multimap that satisfies the predicate. This method is also * commonly called filter. * <p> * <pre>e.g. * return multimap.<b>selectKeysValues</b>(new Predicate2<Integer, Person>() * { * public boolean accept(Integer age, Person person) * { * return (age >= 18) * && (person.getAddress().getCity().equals("Metuchen")); * } * }); * </pre> * <p> * * @param predicate a {@link Predicate2} to use as the select criteria * @return {@code Multimap}, which contains elements as a result of the select criteria * @since 6.0 */ Multimap<K, V> selectKeysValues(Predicate2<? super K, ? super V> predicate); /** * Same as the select method but uses the specified target multimap for the results. * <p> * <pre>e.g. * return multimap.<b>selectKeysValues</b>(new Predicate2<Integer, Person>() * { * public boolean accept(Integer age, Person person) * { * return (age >= 18) * && (person.getAddress().getCity().equals("Metuchen")); * } * }, FastListMultimap.newMultimap()); * </pre> * <p> * * @param predicate a {@link Predicate2} to use as the select criteria * @param target the Multimap to append to for all elements in this {@code Multimap} that satisfy the {@code predicate} * @return {@code target}, which contains appended elements as a result of the select criteria * @since 6.0 */ <R extends MutableMultimap<K, V>> R selectKeysValues(Predicate2<? super K, ? super V> predicate, R target); /** * Returns all elements of the source multimap that don't satisfy the predicate. * <p> * <pre>e.g. * return multimap.<b>rejectKeysValues</b>(new Predicate2<Integer, Person>() * { * public boolean accept(Integer age, Person person) * { * return (age >= 18) * && (person.getAddress().getCity().equals("Metuchen")); * } * }); * </pre> * <p> * * @param predicate a {@link Predicate2} to use as the reject criteria * @return {@code Multimap}, which contains elements that don't satisfy the {@code predicate} * @since 6.0 */ Multimap<K, V> rejectKeysValues(Predicate2<? super K, ? super V> predicate); /** * Same as the reject method but uses the specified target multimap for the results. * <p> * <pre>e.g. * return multimap.<b>rejectKeysValues</b>(new Predicate2<Integer, Person>() * { * public boolean accept(Integer age, Person person) * { * return (age >= 18) * && (person.getAddress().getCity().equals("Metuchen")); * } * }, FastListMultimap.newMultimap()); * </pre> * <p> * * @param predicate a {@link Predicate2} to use as the reject criteria * @param target the Multimap to append to for all elements in this {@code Multimap} that don't satisfy the {@code predicate} * @return {@code target}, which contains appended elements that don't satisfy the {@code predicate} * @since 6.0 */ <R extends MutableMultimap<K, V>> R rejectKeysValues(Predicate2<? super K, ? super V> predicate, R target); /** * Returns all elements of the source multimap that satisfies the predicate. This method is also * commonly called filter. * <p> * <pre>e.g. * return multimap.<b>selectKeysMultiValues</b>(new Predicate2<Integer, Iterable<Person>>() * { * public boolean accept(Integer age, Iterable<Person> values) * { * return (age >= 18) * && ((RichIterable<Person>)values.size() >= 2); * } * }); * </pre> * <p> * * @param predicate a {@link Predicate2} to use as the select criteria * @return {@code Multimap}, which contains elements as a result of the select criteria * @since 6.0 */ Multimap<K, V> selectKeysMultiValues(Predicate2<? super K, ? super Iterable<V>> predicate); /** * Same as the select method but uses the specified target multimap for the results. * <p> * <pre>e.g. * return multimap.<b>selectKeysMultiValues</b>(new Predicate2<Integer, Iterable<Person>>() * { * public boolean accept(Integer age, Iterable<Person> values) * { * return (age >= 18) * && ((RichIterable<Person>)values.size() >= 2); * } * }, FastListMultimap.newMultimap()); * </pre> * <p> * * @param predicate a {@link Predicate2} to use as the select criteria * @param target the Multimap to append to for all elements in this {@code Multimap} that satisfy the {@code predicate} * @return {@code target}, which contains appended elements as a result of the select criteria * @since 6.0 */ <R extends MutableMultimap<K, V>> R selectKeysMultiValues(Predicate2<? super K, ? super Iterable<V>> predicate, R target); /** * Returns all elements of the source multimap that don't satisfy the predicate. * <p> * <pre>e.g. * return multimap.<b>rejectKeysMultiValues</b>(new Predicate2<Integer, Iterable<Person>>() * { * public boolean accept(Integer age, Iterable<Person> values) * { * return (age >= 18) * && ((RichIterable<Person>)values.size() >= 2); * } * }); * </pre> * <p> * * @param predicate a {@link Predicate2} to use as the reject criteria * @return {@code Multimap}, which contains elements that don't satisfy the {@code predicate} * @since 6.0 */ Multimap<K, V> rejectKeysMultiValues(Predicate2<? super K, ? super Iterable<V>> predicate); /** * Same as the reject method but uses the specified target multimap for the results. * <p> * <pre>e.g. * return multimap.<b>rejectKeysMultiValues</b>(new Predicate2<Integer, Iterable<Person>>() * { * public boolean accept(Integer age, Iterable<Person> values) * { * return (age >= 18) * && ((RichIterable<Person>)values.size() >= 2); * } * }, FastListMultimap.newMultimap()); * </pre> * <p> * * @param predicate a {@link Predicate2} to use as the reject criteria * @param target the Multimap to append to for all elements in this {@code Multimap} that don't satisfy the {@code predicate} * @return {@code target}, which contains appended elements that don't satisfy the {@code predicate} * @since 6.0 */ <R extends MutableMultimap<K, V>> R rejectKeysMultiValues(Predicate2<? super K, ? super Iterable<V>> predicate, R target); /** * Returns a new multimap with the results of applying the specified function on each key and value of the source * multimap. This method is also commonly called transform or map. * <p> * <pre>e.g. * return multimap.collectKeysValues(new Function2<Integer, Person, Pair<String, String>>() * { * public Pair<String, String> valueOf(Integer age, Person person) * { * return Tuples.pair(age.toString(), person.getLastName()); * } * }); * </pre> * * @param function a {@link Function2} to use for transformation * @return {@code Multimap}, which contains elements as a result of the transformation * @since 6.0 */ <K2, V2> Multimap<K2, V2> collectKeysValues(Function2<? super K, ? super V, Pair<K2, V2>> function); /** * Same as the collect method but uses the specified target multimap for the results. * <p> * <pre>e.g. * return multimap.collectKeysValues(new Function2<Integer, Person, Pair<String, String>>() * { * public Pair<String, String> valueOf(Integer age, Person person) * { * return Tuples.pair(age.toString(), person.getLastName()); * } * }, HashBagMultimap.<String, String>newMultimap()); * </pre> * * @param function a {@link Function2} to use for transformation * @param target the Multimap to append for all elements in this {@code Multimap} that are evaluated in {@code function} * @return {@code target}, which contains appended elements as a result of the transformation * @since 6.0 */ <K2, V2, R extends MutableMultimap<K2, V2>> R collectKeysValues(Function2<? super K, ? super V, Pair<K2, V2>> function, R target); /** * Returns a new multimap with the results of applying the specified function on each value of the source * multimap. This method is also commonly called transform or map. * <p> * <pre>e.g. * return multimap.collectValues(new Function<Person, String>() * { * public String valueOf(Person person) * { * return person.getLastName(); * } * }); * </pre> * * @param function a {@link Function} to use for transformation * @return {@code Multimap}, which contains elements as a result of the transformation * @since 6.0 */ <V2> Multimap<K, V2> collectValues(Function<? super V, ? extends V2> function); /** * Same as the collect method but uses the specified target multimap for the results. * <p> * <pre>e.g. * return multimap.collectValues(new Function<Person, String>() * { * public String valueOf(Person person) * { * return person.getLastName(); * } * }, FastListMultimap.<Integer, String>newMultimap()); * </pre> * * @param function a {@link Function} to use for transformation * @param target the Multimap to append for all elements in this {@code Multimap} that are evaluated in {@code function} * @return {@code target}, which contains appended elements as a result of the transformation * @since 6.0 */ <V2, R extends MutableMultimap<K, V2>> R collectValues(Function<? super V, ? extends V2> function, R target); }