All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sirius.kernel.commons.Tuple Maven / Gradle / Ivy

/*
 * Made with all the love in the world
 * by scireum in Remshalden, Germany
 *
 * Copyright by scireum GmbH
 * http://www.scireum.de - [email protected]
 */

package sirius.kernel.commons;

import com.google.common.base.Objects;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Stream;

/**
 * Represents a tuple of two values with two arbitrary types.
 * 

* If the first type is comparable and should be used to compare the tuples, {@link ComparableTuple} can be used. * * @param defines the first type of the tuple * @param defines the second type of the tuple * @see Tuple * @see Comparable */ public class Tuple { private F first; private S second; /** * Creates a tuple with a givens value for first and second *

* Can be used to specify the generic types for F and S. Otherwise, the create methods can be used. * * @param first defines the value to be used for the first component of the tuple * @param second defines the value to be used for the second component of the tuple */ public Tuple(F first, S second) { super(); this.first = first; this.second = second; } /** * Creates a new tuple with both values set to null * * @param defines the first type of the tuple * @param defines the second type of the tuple * @return the newly created tuple */ public static Tuple create() { return new Tuple<>(null, null); } /** * Creates a tuple with a given value for first * * @param first defines the value to be used for the first component of the tuple * @param defines the first type of the tuple * @param defines the second type of the tuple * @return the newly created tuple */ public static Tuple create(F first) { return new Tuple<>(first, null); } /** * Creates a tuple with a givens value for first and second * * @param first defines the value to be used for the first component of the tuple * @param second defines the value to be used for the second component of the tuple * @param defines the first type of the tuple * @param defines the second type of the tuple * @return the newly created tuple */ public static Tuple create(F first, S second) { return new Tuple<>(first, second); } /** * Returns the first component of the tuple * * @return the first component of the tuple */ public F getFirst() { return first; } /** * Sets the first component of the tuple to the given value. * * @param first defines the value to be used as the first component of the tuple */ public void setFirst(F first) { this.first = first; } /** * Returns the second component of the tuple * * @return the second component of the tuple */ public S getSecond() { return second; } /** * Sets the second component of the tuple to the given value. * * @param second defines the value to be used as the second component of the tuple */ public void setSecond(S second) { this.second = second; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof Tuple)) { return false; } Tuple other = (Tuple) obj; return Objects.equal(first, other.getFirst()) && Objects.equal(second, other.getSecond()); } @Override public String toString() { return first + ": " + second; } @Override public int hashCode() { return Objects.hashCode(first, second); } /** * Extracts all first components of the given collection of tuples and returns them as list. * * @param tuples the collection of tuples to process * @param the type of the tuples involved * @param the type of the first elements of the tuples * @param the type of the second elements of the tuples * @return a list containing each first component of the collection of given tuples. */ public static , K, V> List firsts(@Nonnull Collection tuples) { List result = new ArrayList<>(tuples.size()); for (Tuple t : tuples) { result.add(t.getFirst()); } return result; } /** * Extracts all second components of the given collection of tuples and returns them as list. * * @param tuples the collection of tuples to process * @param the type of the tuples involved * @param the type of the first elements of the tuples * @param the type of the second elements of the tuples * @return a list containing each second component of the collection of given tuples. */ public static , K, V> List seconds(@Nonnull Collection tuples) { List result = new ArrayList<>(tuples.size()); for (Tuple t : tuples) { result.add(t.getSecond()); } return result; } /** * Converts a map into a list of tuples. * * @param map the map to be converted * @param the key type of the map and therefore the type of the first component of the tuples * @param the value type of the map and therefore the type of the second component of the tuples * @return a list of tuples, containing one tuple per map entry where the first component is the key, * and the second component is the value of the map entry. */ public static List> fromMap(@Nonnull Map map) { List> result = new ArrayList<>(map.size()); for (Map.Entry e : map.entrySet()) { result.add(new Tuple<>(e.getKey(), e.getValue())); } return result; } /** * Converts a collection of tuples into a map * * @param values the collection of tuples to be converted * @param the key type of the map and therefore the type of the first component of the tuples * @param the value type of the map and therefore the type of the second component of the tuples * @return a map containing an entry for each tuple in the collection, where the key is the first component of the * tuple and the value is the second component of the tuple. If two tuples have equal values as first * component, the specific map entry will be overridden in the order defined in the given collection. */ public static Map toMap(@Nonnull Collection> values) { Map result = new HashMap<>(); for (Tuple e : values) { result.put(e.getFirst(), e.getSecond()); } return result; } /** * Provides a {@link Collector} which can be used to collect a {@link Stream} of tuples into a {@link Map}. *

* As an example: {@code aStream.collect(Tuple.toMap(HashMap::new, (a, b) -> b))} will transform the * stream of tuples into a map where a later key value pair will overwrite earlier ones. * * @param supplier factory for generating the result map * @param merger used to decide which value to keep on a key collision * @param key type of the tuples being processed * @param value type of the tuples being processed * @return a Collector which transforms a stream of tuples into a map * @see #toMap(java.util.function.Supplier) */ public static Collector, Map, Map> toMap(Supplier> supplier, BinaryOperator merger) { return Collector.of(supplier, (map, tuple) -> map.put(tuple.getFirst(), tuple.getSecond()), (a, b) -> { b.entrySet() .forEach(entryInB -> a.compute(entryInB.getKey(), (key, valueOfA) -> merger.apply(valueOfA, entryInB.getValue()))); return a; }, Function.identity(), Collector.Characteristics.IDENTITY_FINISH); } /** * Provides a {@link Collector} which can be used to collect a {@link Stream} of tuples into a {@link Map}. *

* Key collisions are automatically handled by choosing the later entry (updating the map). * * @param supplier factory for generating the result map * @param key type of the tuples being processed * @param value type of the tuples being processed * @return a Collector which transforms a stream of tuples into a map */ public static Collector, Map, Map> toMap(Supplier> supplier) { return toMap(supplier, (a, b) -> b); } /** * Provides a {@link Collector} which can be used to collect a {@link Stream} of tuples into a {@link MultiMap}. *

* The type of MultiMap used can be determined by the supplier. So for example * {@code MultiMap::createOrdered} will create a map with ordered keys. * * @param supplier factory for generating the result map * @param key type of the tuples being processed * @param value type of the tuples being processed * @return a Collector which transforms a stream of tuples into a multi map */ public static Collector, MultiMap, MultiMap> toMultiMap(Supplier> supplier) { return Collector.of(supplier, (map, tuple) -> map.put(tuple.getFirst(), tuple.getSecond()), (a, b) -> a.merge(b), Function.identity(), Collector.Characteristics.IDENTITY_FINISH); } /** * Maps an entry which contains a collection as value into a {@link java.util.stream.Stream} of tuples, containing * the key of the entry along with a value of the collection. *

* This method is designed to be used with {@link Stream#flatMap(java.util.function.Function)}: *

     * {@code
     *      map.entrySet().flatMap(e -> Tuple.flatten(e)).forEach(t -> System.out.println(t));
     * }
     * 
* * @param entry the entry to transform * @param the key type of the entry * @param the value type of the entry * @return a Stream of tuples representing the original entry */ public static Stream> flatten(Map.Entry> entry) { return entry.getValue().stream().map(v -> Tuple.create(entry.getKey(), v)); } /** * Converts a {@link java.util.Map.Entry} into a tuple. * * @param entry the entry to convert * @param the key type of the entry * @param the value type of the entry * @return a tuple containing the key as first and the value as second parameter */ public static Tuple valueOf(Map.Entry entry) { return Tuple.create(entry.getKey(), entry.getValue()); } }