package com.medallia.word2vec.util; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; import com.google.common.collect.Sets; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; /** * Simple class for storing two arbitrary objects in one. * * @param <K> the type of the first value * @param <V> the type of the second value */ public class Pair<K, V> implements Map.Entry<K, V>, Serializable { /** @see Serializable */ private static final long serialVersionUID = 1L; /** The first item in the pair. */ public final K first; /** The second item in the pair. */ public final V second; /** Creates a new instance of Pair */ protected Pair(K first, V second) { this.first = first; this.second = second; } /** Type-inferring constructor */ public static <X,Y> Pair<X,Y> cons(X x, Y y) { return new Pair<X,Y>(x,y); } /** Type-inferring constructor for pairs of the same type, which can optionally be swapped */ public static <X> Pair<X,X> cons(X x, X y, boolean swapped) { return swapped ? new Pair<X, X>(y, x) : new Pair<X, X>(x, y); } @Override public int hashCode() { // Compute by hand instead of using Encoding.combineHashes for improved performance return (first == null ? 0 : first.hashCode() * 13) + (second == null ? 0 : second.hashCode() * 17); } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null || !getClass().equals(o.getClass())) return false; Pair<?,?> op = (Pair<?,?>) o; return Objects.equals(op.first, first) && Objects.equals(op.second, second); } /** @return {@link #first}; needed because String Templates have 'first' as a reserved word. */ public K getOne() { return first; } /** @return {@link #first} */ public K getFirst() { return first; } /** @return {@link #second} */ public V getSecond() { return second; } @Override public String toString() { return "Pair<"+first+","+second+">"; } /** @return a list with the two elements from this pair, regardless of whether they are null or not */ public List<Object> asList() { return Lists.newArrayList(first, second); } /** * @return a list of key/value pairs (keys are at even indices, values at odd) taken from the * given array, whose length must be even. */ @SafeVarargs public static <X> List<Pair<X, X>> fromPairs(X... args) { if (Common.isOdd(args.length)) throw new IllegalArgumentException("Array length must be even: " + args.length); List<Pair<X, X>> l = new ArrayList<>(args.length / 2); for (int i = 0; i < args.length; i += 2) l.add(Pair.cons(args[i], args[i + 1])); return l; } /** * Converts a Map to a List of pairs. * Each entry in the map results in a Pair in the returned list. */ public static <X, Y> List<Pair<X, Y>> fromMap(Map<X, Y> m) { List<Pair<X, Y>> l = new ArrayList<>(); for (Map.Entry<X, Y> me : m.entrySet()) { l.add(Pair.cons(me.getKey(), me.getValue())); } return l; } private static <X, Y, C extends Collection<Pair<X, Y>>> C fromMapFlatten(C c, Map<? extends X, ? extends Collection<? extends Y>> m) { for (Map.Entry<? extends X, ? extends Collection<? extends Y>> me : m.entrySet()) { for (Y y : me.getValue()) c.add(Pair.<X, Y>cons(me.getKey(), y)); } return c; } @Override public K getKey() { return first; } @Override public V getValue() { return second; } @Override public V setValue(V value) { throw new UnsupportedOperationException(); } /** Method that allows Pair to be used directly by the Setup system (wtf) */ public String getName() { return String.valueOf(second); } /** @return a reversed version of this pair */ public Pair<V, K> swapped() { return Pair.cons(second, first); } /** @return {@link Function} which performs a {@link #swapped()} */ public static <K, V> Function<Pair<K, V>, Pair<V, K>> swappedFunction() { return new Function<Pair<K, V>, Pair<V, K>>() { @Override public Pair<V, K> apply(Pair<K, V> p) { return p.swapped(); } }; } /** * @return {@link Ordering} which compares the first value of the pairs. * Pairs with equal first value will be considered equivalent independent of the second value */ public static <X extends Comparable<? super X>> Ordering<Pair<X, ?>> firstComparator() { return new Ordering<Pair<X, ?>>() { @Override public int compare(Pair<X, ?> o1, Pair<X, ?> o2) { return Compare.compare(o1.first, o2.first); } }; } /** * @return {@link Ordering} which compares the second value of the pairs. * Pairs with equal second value will be considered equivalent independent of the first value */ public static <Y extends Comparable<? super Y>> Ordering<Pair<?, Y>> secondComparator() { return new Ordering<Pair<?, Y>>() { @Override public int compare(Pair<?, Y> o1, Pair<?, Y> o2) { return Compare.compare(o1.second, o2.second); } }; } /** @return {@link Ordering} which compares both values of the {@link Pair}s, with the first taking precedence. */ public static <X extends Comparable<? super X>, Y extends Comparable<? super Y>> Ordering<Pair<X,Y>> firstThenSecondComparator() { return new Ordering<Pair<X,Y>>() { @Override public int compare(Pair<X, Y> o1, Pair<X, Y> o2) { int k = Compare.compare(o1.first, o2.first); if (k == 0) k = Compare.compare(o1.second, o2.second); return k; } }; } /** @return {@link Ordering} which compares both values of the {@link Pair}s, with the second taking precedence. */ public static <X extends Comparable<? super X>, Y extends Comparable<? super Y>> Ordering<Pair<X,Y>> secondThenFirstComparator() { return new Ordering<Pair<X,Y>>() { @Override public int compare(Pair<X, Y> o1, Pair<X, Y> o2) { int k = Compare.compare(o1.second, o2.second); if (k == 0) k = Compare.compare(o1.first, o2.first); return k; } }; } /** * Pair comparator that applies the given {@link Comparator} to the first value of the pairs */ public static <X, Y> Comparator<Pair<X,Y>> firstComparator(final Comparator<? super X> comp) { return new Comparator<Pair<X,Y>>() { @Override public int compare(Pair<X, Y> o1, Pair<X, Y> o2) { return comp.compare(o1.first, o2.first); } }; } /** * Pair comparator that applies the given {@link Comparator} to the second value of the pairs */ public static <X, Y> Comparator<Pair<X,Y>> secondComparator(final Comparator<? super Y> comp) { return new Comparator<Pair<X,Y>>() { @Override public int compare(Pair<X, Y> o1, Pair<X, Y> o2) { return comp.compare(o1.second, o2.second); } }; } /** * Pair comparator that compares both values of the pairs, with the first taking * precedence; the order is reversed for the first value only. */ public static <X extends Comparable<? super X>, Y extends Comparable<? super Y>> Comparator<Pair<X,Y>> bothFirstReversedComparator() { return new Comparator<Pair<X,Y>>() { @Override public int compare(Pair<X, Y> o1, Pair<X, Y> o2) { int k = Compare.compare(o2.first, o1.first); if (k == 0) k = Compare.compare(o1.second, o2.second); return k; } }; } private static <X, Y> Map<X, Y> fillMap(Map<X, Y> m, Iterable<? extends Pair<? extends X, ? extends Y>> pairs) { for (Pair<? extends X, ? extends Y> p : pairs) { m.put(p.first, p.second); } return m; } /** @return the combination of all the elements in each collection. For instance if the first collection is * {@code [1, 2, 3]}, and the second one is {@code [a, b]}, then the result is {@code [(1, a), (1, b), (2, a), ...]} */ @SuppressWarnings("unchecked") public static <X, Y> List<Pair<X, Y>> cartesianProduct(Collection<X> c1, Collection<Y> c2) { return FluentIterable.from(Sets.cartesianProduct(ImmutableSet.copyOf(c1), ImmutableSet.copyOf(c2))) .transform(new Function<List<Object>, Pair<X, Y>>() { @Override public Pair<X, Y> apply(List<Object> objs) { X x = (X) objs.get(0); Y y = (Y) objs.get(1); return Pair.<X, Y>cons(x, y); } }) .toList(); } /** @return the elements at equal indices in the two lists, which must be of the same * length, as pairs. */ public static <X, Y> List<Pair<X, Y>> zip(Collection<X> c1, Collection<Y> c2) { return zip(c1, c2, new ArrayList<Pair<X, Y>>(c1.size()), false); } /** @return the elements at equal indices in the two lists, which must be of the same * length, as pairs. */ public static <X, Y> List<Pair<X, Y>> zip(X[] a1, Y[] a2) { return zip(ImmutableList.copyOf(a1), ImmutableList.copyOf(a2)); } /** * @return the elements at equal indices in the two lists, which must be of * the same length, as pairs, without duplicates removed from the * first list */ public static <X, Y> List<Pair<X, Y>> zipUnique(Collection<X> c1, Collection<Y> c2) { return zip(c1, c2, new ArrayList<Pair<X, Y>>(), true); } private static <X, Y> List<Pair<X, Y>> zip(Collection<X> c1, Collection<Y> c2, List<Pair<X, Y>> output, boolean uniqueKeys) { int size = c1.size(); if (size != c2.size()) throw new IllegalArgumentException("Collections must be of same size: " + size + ", " + c2.size()); Set<X> set = uniqueKeys ? new HashSet<X>() : null; Iterator<X> it1 = c1.iterator(); Iterator<Y> it2 = c2.iterator(); while (it1.hasNext() && it2.hasNext()) { X x = it1.next(); Y y = it2.next(); if (set == null || set.add(x)) output.add(Pair.cons(x, y)); } return output; } /** * @return the elements at equal indices of the two list as pairs. The number of elements in the result list * is the minimum of the given iterable * of different size only elements at indices * present on the first {@link Iterable} are used. */ public static <X, Y> Iterable<Pair<X, Y>> zipInner(final Iterable<X> first, final Iterable<Y> second) { return new Iterable<Pair<X, Y>>() { @Override public Iterator<Pair<X, Y>> iterator() { final Iterator<X> x = first.iterator(); final Iterator<Y> y = second.iterator(); return new Iterator<Pair<X, Y>>() { @Override public boolean hasNext() { return x.hasNext() && y.hasNext(); } @Override public Pair<X, Y> next() { return Pair.cons(x.next(), y.next()); } @Override public void remove() { x.remove(); y.remove(); } }; } }; } /** @return {@link Function} which retrieves the second of the pair */ public static <V> Function<Pair<?, V>, V> retrieveSecondFunction() { return new Function<Pair<?, V>, V>() { @Override public V apply(Pair<?, V> p) { return p.second; } }; } /** @return {@link Iterable} of second element in pair */ public static <K, V> Iterable<V> unzipSecond(Iterable<Pair<K, V>> pairs) { return Iterables.transform(pairs, Pair.<V>retrieveSecondFunction()); } /** @return {@link Function} which maps the value of each pair through the given {@link Function} */ public static <K, V, V2> Function<Pair<K, V>, Pair<K, V2>> mapValues(final Function<? super V, V2> func) { return new Function<Pair<K, V>, Pair<K, V2>>() { @Override public Pair<K, V2> apply(Pair<K, V> p) { return Pair.cons(p.first, func.apply(p.second)); } }; } /** @return the first value, or null if the pair is null */ public static <K> K firstOrNull(Pair<K, ?> pair) { return pair != null ? pair.first : null; } /** @return the second value, or null if the pair is null */ public static <V> V secondOrNull(Pair<?, V> pair) { return pair != null ? pair.second : null; } /** @return {@link Predicates} which filters only on the first value */ public static <K, V> Predicate<Pair<K, V>> getFirstPredicate(final Predicate<? super K> pred) { return new Predicate<Pair<K, V>>() { @Override public boolean apply(Pair<K, V> pair) { return pred.apply(pair.first); } }; } /** @return {@link Predicates} which filters only on the second value */ public static <K, V> Predicate<Pair<K, V>> getSecondPredicate(final Predicate<? super V> pred) { return new Predicate<Pair<K, V>>() { @Override public boolean apply(Pair<K, V> pair) { return pred.apply(pair.second); } }; } /** @return {@link Predicates} which accepts a pair only if both values are accepted */ public static <K, V> Predicate<Pair<K, V>> getAndPredicate(final Predicate<? super K> firstPred, final Predicate<? super V> secondPred) { return new Predicate<Pair<K, V>>() { @Override public boolean apply(Pair<K, V> pair) { return firstPred.apply(pair.first) && secondPred.apply(pair.second); } }; } /** @return {@link Predicates} which accepts a pair if either values is accepted */ public static <K, V> Predicate<Pair<K, V>> getOrPredicate(final Predicate<? super K> firstPred, final Predicate<? super V> secondPred) { return new Predicate<Pair<K, V>>() { @Override public boolean apply(Pair<K, V> pair) { return firstPred.apply(pair.first) || secondPred.apply(pair.second); } }; } /** * @return {@link ImmutableList} containing all values paired with their applied value * through the function */ public static <X, Y> ImmutableList<Pair<X, Y>> toPairList(Iterable<X> values, Function<X, Y> func) { ImmutableList.Builder<Pair<X, Y>> result = ImmutableList.builder(); for (X x : values) result.add(Pair.cons(x, func.apply(x))); return result.build(); } }