/* __ __ __ __ __ ___ * \ \ / / \ \ / / __/ * \ \/ / /\ \ \/ / / * \____/__/ \__\____/__/.ɪᴏ * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ */ package io.vavr.collection; import io.vavr.Tuple2; import java.io.Serializable; import java.util.ArrayList; import java.util.Comparator; import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; /** * A {@link LinkedHashMap}-based implementation of {@link Multimap} * * @param <K> Key type * @param <V> Value type * @author Ruslan Sennov */ public final class LinkedHashMultimap<K, V> extends AbstractMultimap<K, V, LinkedHashMultimap<K, V>> implements Serializable { private static final long serialVersionUID = 1L; public static <V> Builder<V> withSeq() { return new Builder<>(ContainerType.SEQ, List::empty); } public static <V> Builder<V> withSet() { return new Builder<>(ContainerType.SET, HashSet::empty); } public static <V extends Comparable<? super V>> Builder<V> withSortedSet() { return new Builder<>(ContainerType.SORTED_SET, TreeSet::empty); } public static <V> Builder<V> withSortedSet(Comparator<? super V> comparator) { return new Builder<>(ContainerType.SORTED_SET, () -> TreeSet.empty(comparator)); } public static class Builder<V> { private final ContainerType containerType; private final SerializableSupplier<Traversable<?>> emptyContainer; private Builder(ContainerType containerType, SerializableSupplier<Traversable<?>> emptyContainer) { this.containerType = containerType; this.emptyContainer = emptyContainer; } public <K, V2 extends V> LinkedHashMultimap<K, V2> empty() { return new LinkedHashMultimap<>(LinkedHashMap.empty(), containerType, emptyContainer); } public <K, V2 extends V> LinkedHashMultimap<K, V2> ofEntries(Iterable<? extends Tuple2<? extends K, ? extends V2>> entries) { Objects.requireNonNull(entries, "entries is null"); LinkedHashMultimap<K, V2> result = empty(); for (Tuple2<? extends K, ? extends V2> entry : entries) { result = result.put(entry._1, entry._2); } return result; } @SafeVarargs public final <K, V2 extends V> LinkedHashMultimap<K, V2> ofEntries(Tuple2<? extends K, ? extends V2>... entries) { Objects.requireNonNull(entries, "entries is null"); LinkedHashMultimap<K, V2> result = empty(); for (Tuple2<? extends K, ? extends V2> entry : entries) { result = result.put(entry._1, entry._2); } return result; } @SafeVarargs public final <K, V2 extends V> LinkedHashMultimap<K, V2> ofEntries(java.util.Map.Entry<? extends K, ? extends V2>... entries) { Objects.requireNonNull(entries, "entries is null"); LinkedHashMultimap<K, V2> result = empty(); for (java.util.Map.Entry<? extends K, ? extends V2> entry : entries) { result = result.put(entry.getKey(), entry.getValue()); } return result; } /** * Returns a {@code LinkedHashMultimap}, from a source java.util.Map. * * @param map A map * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given map entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> ofAll(java.util.Map<? extends K, ? extends V2> map) { return Multimaps.ofJavaMap(empty(), map); } /** * Returns a {@code LinkedHashMultimap}, from entries mapped from stream. * * @param stream the source stream * @param keyMapper the key mapper * @param valueMapper the value mapper * @param <T> The stream element type * @param <K> The key type * @param <V2> The value type * @return A new Multimap */ public <T, K, V2 extends V> LinkedHashMultimap<K, V2> ofAll(java.util.stream.Stream<? extends T> stream, Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends V2> valueMapper) { return Multimaps.ofStream(empty(), stream, keyMapper, valueMapper); } /** * Returns a {@code LinkedHashMultimap}, from entries mapped from stream. * * @param stream the source stream * @param entryMapper the entry mapper * @param <T> The stream element type * @param <K> The key type * @param <V2> The value type * @return A new Multimap */ public <T, K, V2 extends V> LinkedHashMultimap<K, V2> ofAll(java.util.stream.Stream<? extends T> stream, Function<? super T, Tuple2<? extends K, ? extends V2>> entryMapper) { return Multimaps.ofStream(empty(), stream, entryMapper); } @SuppressWarnings("unchecked") public <K, V2 extends V> LinkedHashMultimap<K, V2> tabulate(int n, Function<? super Integer, ? extends Tuple2<? extends K, ? extends V2>> f) { Objects.requireNonNull(f, "f is null"); return ofEntries(Collections.tabulate(n, (Function<? super Integer, ? extends Tuple2<K, V2>>) f)); } @SuppressWarnings("unchecked") public <K, V2 extends V> LinkedHashMultimap<K, V2> fill(int n, Supplier<? extends Tuple2<? extends K, ? extends V2>> s) { Objects.requireNonNull(s, "s is null"); return ofEntries(Collections.fill(n, (Supplier<? extends Tuple2<K, V2>>) s)); } /** * Creates a LinkedHashMultimap of the given key-value pair. * * @param key A singleton map key. * @param value A singleton map value. * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> of(K key, V2 value) { final LinkedHashMultimap<K, V2> e = empty(); return e.put(key, value); } /** * Creates a LinkedHashMultimap of the given list of key-value pairs. * * @param k1 a key for the map * @param v1 the value for k1 * @param k2 a key for the map * @param v2 the value for k2 * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> of(K k1, V2 v1, K k2, V2 v2) { return of(k1, v1).put(k2, v2); } /** * Creates a LinkedHashMultimap of the given list of key-value pairs. * * @param k1 a key for the map * @param v1 the value for k1 * @param k2 a key for the map * @param v2 the value for k2 * @param k3 a key for the map * @param v3 the value for k3 * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> of(K k1, V2 v1, K k2, V2 v2, K k3, V2 v3) { return of(k1, v1, k2, v2).put(k3, v3); } /** * Creates a LinkedHashMultimap of the given list of key-value pairs. * * @param k1 a key for the map * @param v1 the value for k1 * @param k2 a key for the map * @param v2 the value for k2 * @param k3 a key for the map * @param v3 the value for k3 * @param k4 a key for the map * @param v4 the value for k4 * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> of(K k1, V2 v1, K k2, V2 v2, K k3, V2 v3, K k4, V2 v4) { return of(k1, v1, k2, v2, k3, v3).put(k4, v4); } /** * Creates a LinkedHashMultimap of the given list of key-value pairs. * * @param k1 a key for the map * @param v1 the value for k1 * @param k2 a key for the map * @param v2 the value for k2 * @param k3 a key for the map * @param v3 the value for k3 * @param k4 a key for the map * @param v4 the value for k4 * @param k5 a key for the map * @param v5 the value for k5 * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> of(K k1, V2 v1, K k2, V2 v2, K k3, V2 v3, K k4, V2 v4, K k5, V2 v5) { return of(k1, v1, k2, v2, k3, v3, k4, v4).put(k5, v5); } /** * Creates a LinkedHashMultimap of the given list of key-value pairs. * * @param k1 a key for the map * @param v1 the value for k1 * @param k2 a key for the map * @param v2 the value for k2 * @param k3 a key for the map * @param v3 the value for k3 * @param k4 a key for the map * @param v4 the value for k4 * @param k5 a key for the map * @param v5 the value for k5 * @param k6 a key for the map * @param v6 the value for k6 * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> of(K k1, V2 v1, K k2, V2 v2, K k3, V2 v3, K k4, V2 v4, K k5, V2 v5, K k6, V2 v6) { return of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5).put(k6, v6); } /** * Creates a LinkedHashMultimap of the given list of key-value pairs. * * @param k1 a key for the map * @param v1 the value for k1 * @param k2 a key for the map * @param v2 the value for k2 * @param k3 a key for the map * @param v3 the value for k3 * @param k4 a key for the map * @param v4 the value for k4 * @param k5 a key for the map * @param v5 the value for k5 * @param k6 a key for the map * @param v6 the value for k6 * @param k7 a key for the map * @param v7 the value for k7 * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> of(K k1, V2 v1, K k2, V2 v2, K k3, V2 v3, K k4, V2 v4, K k5, V2 v5, K k6, V2 v6, K k7, V2 v7) { return of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6).put(k7, v7); } /** * Creates a LinkedHashMultimap of the given list of key-value pairs. * * @param k1 a key for the map * @param v1 the value for k1 * @param k2 a key for the map * @param v2 the value for k2 * @param k3 a key for the map * @param v3 the value for k3 * @param k4 a key for the map * @param v4 the value for k4 * @param k5 a key for the map * @param v5 the value for k5 * @param k6 a key for the map * @param v6 the value for k6 * @param k7 a key for the map * @param v7 the value for k7 * @param k8 a key for the map * @param v8 the value for k8 * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> of(K k1, V2 v1, K k2, V2 v2, K k3, V2 v3, K k4, V2 v4, K k5, V2 v5, K k6, V2 v6, K k7, V2 v7, K k8, V2 v8) { return of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7).put(k8, v8); } /** * Creates a LinkedHashMultimap of the given list of key-value pairs. * * @param k1 a key for the map * @param v1 the value for k1 * @param k2 a key for the map * @param v2 the value for k2 * @param k3 a key for the map * @param v3 the value for k3 * @param k4 a key for the map * @param v4 the value for k4 * @param k5 a key for the map * @param v5 the value for k5 * @param k6 a key for the map * @param v6 the value for k6 * @param k7 a key for the map * @param v7 the value for k7 * @param k8 a key for the map * @param v8 the value for k8 * @param k9 a key for the map * @param v9 the value for k9 * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> of(K k1, V2 v1, K k2, V2 v2, K k3, V2 v3, K k4, V2 v4, K k5, V2 v5, K k6, V2 v6, K k7, V2 v7, K k8, V2 v8, K k9, V2 v9) { return of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8).put(k9, v9); } /** * Creates a LinkedHashMultimap of the given list of key-value pairs. * * @param k1 a key for the map * @param v1 the value for k1 * @param k2 a key for the map * @param v2 the value for k2 * @param k3 a key for the map * @param v3 the value for k3 * @param k4 a key for the map * @param v4 the value for k4 * @param k5 a key for the map * @param v5 the value for k5 * @param k6 a key for the map * @param v6 the value for k6 * @param k7 a key for the map * @param v7 the value for k7 * @param k8 a key for the map * @param v8 the value for k8 * @param k9 a key for the map * @param v9 the value for k9 * @param k10 a key for the map * @param v10 the value for k10 * @param <K> The key type * @param <V2> The value type * @return A new Multimap containing the given entries */ public <K, V2 extends V> LinkedHashMultimap<K, V2> of(K k1, V2 v1, K k2, V2 v2, K k3, V2 v3, K k4, V2 v4, K k5, V2 v5, K k6, V2 v6, K k7, V2 v7, K k8, V2 v8, K k9, V2 v9, K k10, V2 v10) { return of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9).put(k10, v10); } public <K, V2 extends V> LinkedHashMultimap<K, V2> of(Tuple2<? extends K, ? extends V2> entry) { final LinkedHashMultimap<K, V2> e = empty(); return e.put(entry._1, entry._2); } public <K, V2 extends V> Collector<Tuple2<K, V2>, ArrayList<Tuple2<K, V2>>, Multimap<K, V2>> collector() { final Supplier<ArrayList<Tuple2<K, V2>>> supplier = ArrayList::new; final BiConsumer<ArrayList<Tuple2<K, V2>>, Tuple2<K, V2>> accumulator = ArrayList::add; final BinaryOperator<ArrayList<Tuple2<K, V2>>> combiner = (left, right) -> { left.addAll(right); return left; }; return Collector.of(supplier, accumulator, combiner, this::ofEntries); } } /** * Narrows a widened {@code HashMultimap<? extends K, ? extends V>} to {@code HashMultimap<K, V>} * by performing a type safe-cast. This is eligible because immutable/read-only * collections are covariant. * * @param map A {@code Map}. * @param <K> Key type * @param <V> Value type * @return the given {@code multimap} instance as narrowed type {@code Multimap<K, V>}. */ @SuppressWarnings("unchecked") public static <K, V> LinkedHashMultimap<K, V> narrow(LinkedHashMultimap<? extends K, ? extends V> map) { return (LinkedHashMultimap<K, V>) map; } private LinkedHashMultimap(Map<K, Traversable<V>> back, ContainerType containerType, SerializableSupplier<Traversable<?>> emptyContainer) { super(back, containerType, emptyContainer); } @Override protected <K2, V2> Map<K2, V2> emptyMapSupplier() { return LinkedHashMap.empty(); } @SuppressWarnings("unchecked") @Override protected <K2, V2> LinkedHashMultimap<K2, V2> emptyInstance() { return new LinkedHashMultimap<>(LinkedHashMap.empty(), getContainerType(), emptyContainer); } @Override protected <K2, V2> LinkedHashMultimap<K2, V2> createFromMap(Map<K2, Traversable<V2>> back) { return new LinkedHashMultimap<>(back, getContainerType(), emptyContainer); } @Override public boolean isSequential() { return true; } }