/*
* Copyright 2015 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.map;
import java.util.Map;
import com.gs.collections.api.RichIterable;
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.multimap.Multimap;
import com.gs.collections.api.tuple.Pair;
/**
* A Read-only Map API, with the minor exception inherited from java.lang.Iterable. The method map.iterator().remove()
* will throw an UnsupportedOperationException.
*/
public interface MapIterable<K, V> extends RichIterable<V>
{
/**
* @see Map#get(Object)
*/
V get(Object key);
/**
* @see Map#containsKey(Object)
*/
boolean containsKey(Object key);
/**
* @see Map#containsValue(Object)
*/
boolean containsValue(Object value);
/**
* Calls the procedure with each <em>value</em> of the map.
* <pre>
* Set<String> result = UnifiedSet.newSet();
* MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four");
* map.<b>forEachValue</b>(new CollectionAddProcedure<String>(result));
* Verify.assertSetsEqual(UnifiedSet.newSetWith("One", "Two", "Three", "Four"), result);
* </pre>
*/
void forEachValue(Procedure<? super V> procedure);
/**
* Executes the Procedure for each value of the map and returns {@code this}.
* <p>
* <pre>e.g.
* return peopleByCity.<b>tap</b>(new Procedure<Person>()
* {
* public void value(Person person)
* {
* LOGGER.info(person.getName());
* }
* });
* </pre>
*
* @see #forEach(Procedure)
* @since 6.0
*/
MapIterable<K, V> tap(Procedure<? super V> procedure);
/**
* Calls the {@code procedure} with each <em>key</em> of the map.
* <pre>
* final Collection<Integer> result = new ArrayList<Integer>();
* MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "1", 2, "2", 3, "3");
* map.<b>forEachKey</b>(new CollectionAddProcedure<Integer>(result));
* Verify.assertContainsAll(result, 1, 2, 3);
* </pre>
*/
void forEachKey(Procedure<? super K> procedure);
/**
* Calls the {@code procedure} with each <em>key-value</em> pair of the map.
* <pre>
* final Collection<String> collection = new ArrayList<String>();
* MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three");
* map.<b>forEachKeyValue</b>(new Procedure2<Integer, String>()
* {
* public void value(final Integer key, final String value)
* {
* collection.add(String.valueOf(key) + value);
* }
* });
* Verify.assertContainsAll(collection, "1One", "2Two", "3Three");
* </pre>
*/
void forEachKeyValue(Procedure2<? super K, ? super V> procedure);
/**
* Return the MapIterable that is obtained by flipping the direction of this map and making the associations
* from value to key.
* <pre>
* MapIterable<Integer, String> map = this.newMapWithKeysValues(1, "1", 2, "2", 3, "3");
* MapIterable<String, Integer> result = map.flipUniqueValues();
* Assert.assertTrue(result.equals(UnifiedMap.newWithKeysValues("1", 1, "2", 2, "3", 3)));
* </pre>
*
* @throws IllegalStateException if the MapIterable contains duplicate values.
* @since 5.0
*/
MapIterable<V, K> flipUniqueValues();
/**
* Return the value in the Map that corresponds to the specified key, or if there is no value at the key, return the
* result of evaluating the specified Function0.
*/
V getIfAbsent(K key, Function0<? extends V> function);
/**
* Return the value in the Map that corresponds to the specified key, or if there is no value at the key, return {@code value}.
*/
V getIfAbsentValue(K key, V value);
/**
* Return the value in the Map that corresponds to the specified key, or if there is no value at the key, return the
* result of evaluating the specified function and parameter.
*/
<P> V getIfAbsentWith(K key, Function<? super P, ? extends V> function, P parameter);
/**
* If there is a value in the Map that corresponds to the specified key return the result of applying the specified
* Function on the value, otherwise return null.
*/
<A> A ifPresentApply(K key, Function<? super V, ? extends A> function);
/**
* Returns an unmodifiable lazy iterable wrapped around the keySet for the map
*/
RichIterable<K> keysView();
/**
* Returns an unmodifiable lazy iterable wrapped around the values for the map
*/
RichIterable<V> valuesView();
/**
* Returns an unmodifiable lazy iterable of key/value pairs wrapped around the entrySet for the map
*/
RichIterable<Pair<K, V>> keyValuesView();
/**
* Given a map from Domain -> Range return a multimap from Range -> Domain. We chose the name 'flip'
* rather than 'invert' or 'transpose' since this method does not have the property of applying twice
* returns the original.
* <p>
* Since the keys in the input are unique, the values in the output are unique, so the return type should
* be a SetMultimap. However since SetMultimap and SortedSetMultimap don't inherit from one another, SetMultimap
* here does not allow SortedMapIterable to have a SortedSetMultimap return. Thus we compromise and call this
* Multimap, even though all implementations will be a SetMultimap or SortedSetMultimap.
*
* @since 5.0
*/
Multimap<V, K> flip();
/**
* For each key and value of the map the predicate is evaluated, if the result of the evaluation is true,
* that key and value are returned in a new map.
* <p>
* <pre>e.g.
* peopleByCity.select(new Predicate2<City, Person>()
* {
* public boolean accept(City city, Person person)
* {
* return city.getName().equals("Anytown") && person.getLastName().equals("Smith");
* }
* });
* </pre>
*/
MapIterable<K, V> select(Predicate2<? super K, ? super V> predicate);
/**
* For each key and value of the map the predicate is evaluated, if the result of the evaluation is false,
* that key and value are returned in a new map.
* <p>
* <pre>e.g.
* peopleByCity.reject(new Predicate2<City, Person>()
* {
* public boolean accept(City city, Person person)
* {
* return city.getName().equals("Anytown") && person.getLastName().equals("Smith");
* }
* });
* </pre>
*/
MapIterable<K, V> reject(Predicate2<? super K, ? super V> predicate);
/**
* For each key and value of the map the function is evaluated. The results of these evaluations are returned in
* a new map. The map returned will use the values projected from the function rather than the original values.
* <p>
* <pre>e.g.
* peopleByCity.collect(new Function2<City, Person, String>()
* {
* public String value(City city, Person person)
* {
* return Pair.of(city.getCountry(), person.getAddress().getCity());
* }
* });
* </pre>
*/
<K2, V2> MapIterable<K2, V2> collect(Function2<? super K, ? super V, Pair<K2, V2>> function);
/**
* For each key and value of the map the function is evaluated. The results of these evaluations are returned in
* a new map. The map returned will use the values projected from the function rather than the original values.
* <p>
* <pre>e.g.
* peopleByCity.collectValues(new Function2<City, Person, String>()
* {
* public String value(City city, Person person)
* {
* return person.getFirstName() + " " + person.getLastName();
* }
* });
* </pre>
*/
<R> MapIterable<K, R> collectValues(Function2<? super K, ? super V, ? extends R> function);
/**
* Return the first key and value of the map for which the predicate evaluates to true when they are given
* as arguments. The predicate will only be evaluated until such pair is found or until all of the keys and
* values of the map have been used as arguments. That is, there may be keys and values of the map that are
* never used as arguments to the predicate. The result is null if predicate does not evaluate to true for
* any key/value combination.
* <p>
* <pre>e.g.
* peopleByCity.detect(new Predicate2<City, Person>()
* {
* public boolean accept(City city, Person person)
* {
* return city.getName().equals("Anytown") && person.getLastName().equals("Smith");
* }
* });
* </pre>
*/
Pair<K, V> detect(Predicate2<? super K, ? super V> predicate);
/**
* Follows the same general contract as {@link Map#equals(Object)}.
*/
boolean equals(Object o);
/**
* Follows the same general contract as {@link Map#hashCode()}.
*/
int hashCode();
/**
* Returns a string representation of this MapIterable. The string representation consists of a list of the
* map's key-value pairs in the order they are returned by its iterator. The key and value in each key-value pair are separated
* by a colon (<tt>":"</tt>) and each pair is enclosed in square brackets (<tt>"[]"</tt>). Adjacent key-value pairs
* are separated by the characters <tt>", "</tt> (comma and space). Keys and values are converted to strings as by
* {@link String#valueOf(Object)}.
*
* @return a string representation of this MapIterable
*/
String toString();
ImmutableMapIterable<K, V> toImmutable();
}