package net.sf.jabref.util; import java.util.*; import net.sf.jabref.Util; /** * Class for putting objects of two types together. * * The usual way to use this is like this: * * <pre> * Pair<Integer, String> intStr = new Pair<Integer, String>(5, "Hello"); * * intStr.p == 5 * intStr.v == "Hello" * </pre> * * @author oezbek * * @param <P> First type to be contained in the pair. * @param <V> Second type to be contained in the pair. */ public class Pair<P, V> { /** * Direct access to the p element is allowed. */ public P p; /** * Direct access to the v element is allowed. */ public V v; /** * Constructor that sets the given p and v values. * * @param p * @param v */ public Pair(P p, V v) { this.p = p; this.v = v; } /** * Returns a comparator that compares by p. * * @param <V> * The V type is not important for this method. * @param * <P> * The P type of the pair needs to be comparable. * @return A comparator for the p in a pair. */ public static <P extends Comparable<P>, V> Comparator<Pair<P, V>> pCompare() { return new Comparator<Pair<P, V>>() { public int compare(Pair<P, V> arg0, Pair<P, V> arg1) { return arg0.p.compareTo(arg1.p); } }; } /** * Given a comparator for p elements, returns a Comparator for pairs which * uses this given comparator to make the comparison. * * @param <V> * The V-Type of the Pair. * @param * <P> * The P-Type of the Pair. * @param comp * A comparator which will be wrapped so that it can be used to * compare * @return A comparator for Pairs of type P and V which makes use of the * given comparator. */ public static <P> Comparator<? super Pair<P, ?>> pCompare( final Comparator<P> comp) { return new Comparator<Pair<P, ?>>() { public int compare(Pair<P, ?> arg0, Pair<P, ?> arg1) { return comp.compare(arg0.p, arg1.p); } }; } /** * Returns a Pair with the type and the contents of the current Pair flipped * from P to V. * * <pre> * Pair<Integer, String> intString = new Pair<Integer, String>(5, "Hallo"); * Pair<String, Integer> strInteger = intString.flip(); * </pre> */ public Pair<V, P> flip() { return new Pair<V, P>(v, p); } /** * Returns a list of pairs with P and V being switched. * * @param * <P> * @param <V> * @param list * @return */ public static <P, V> List<Pair<V, P>> flipList(List<Pair<P, V>> list) { LinkedList<Pair<V, P>> result = new LinkedList<Pair<V, P>>(); for (Pair<P, V> pair : list) result.add(pair.flip()); return result; } /** * Given a collection of Pair<P,V> it will put all V values that have the * same P-value together in a set and return a collection of those sets with * their associated P. * * Example: * * <pre> * Collection<Pair<Integer, String>> c = new LinkedList<Pair<Integer, String>>(); * c.add(new Pair<Integer, String>(3, "Hallo")); * c.add(new Pair<Integer, String>(4, "Bye")); * c.add(new Pair<Integer, String>(3, "Adios")); * * Collection<Pair<Integer, Set<String>>> result = Pair.disjointPartition(c); * * result == [(3, ["Hallo", "Adios"]), (4, ["Bye"])] * </pre> * * @param * <P> * @param <V> * @param list * @return */ public static <P extends Comparable<P>, V> List<Pair<P, Set<V>>> disjointPartition( List<Pair<P, V>> list) { List<Pair<P, Set<V>>> result = new LinkedList<Pair<P, Set<V>>>(); Comparator<Pair<P, V>> c = Pair.pCompare(); Collections.sort(list, Collections.reverseOrder(c)); Iterator<Pair<P, V>> i = list.iterator(); Set<V> vs; if (i.hasNext()) { Pair<P, V> first = i.next(); P last = first.p; vs = new HashSet<V>(); vs.add(first.v); while (i.hasNext()) { Pair<P, V> next = i.next(); if (last.compareTo(next.p) == 0) { vs.add(next.v); } else { result.add(new Pair<P, Set<V>>(last, vs)); vs = new HashSet<V>(); last = next.p; vs.add(next.v); } } result.add(new Pair<P, Set<V>>(last, vs)); } return result; } /** * Returns a comparator that compares by v. * * @param * <P> * The P type is not important for this method. * @param <V> * The V type of the pair needs to be comparable. * @return A comparator for the v in a pair. */ public static <V extends Comparable<V>> Comparator<? super Pair<?, V>> vCompare() { return new Comparator<Pair<?, V>>() { public int compare(Pair<?, V> arg0, Pair<?, V> arg1) { return arg0.v.compareTo(arg1.v); } }; } /** * Given a comparator for v elements, returns a Comparator for pairs which * uses this given comparator to make the comparison. * * @param * <P> * The P-Type of the Pair. * @param <V> * The V-Type of the Pair. * @param vComp * A comparator which will be wrapped so that it can be used to * compare * @return A comparator for Pairs of type P and V which makes use of the * given comparator. */ public static <V> Comparator<? super Pair<?,V>> vCompare( final Comparator<V> vComp) { return new Comparator<Pair<?, V>>() { public int compare(Pair<?, V> arg0, Pair<?, V> arg1) { return vComp.compare(arg0.v, arg1.v); } }; } /** * Takes a list of P and list of V and returns a list of Pair<P,V>. If the * lengths of the lists differ missing values are padded by null. * * @param * <P> * @param <V> * @param ps * @param vs * @return */ public static <P, V> List<Pair<P, V>> zip(List<P> ps, List<V> vs) { List<Pair<P, V>> result = new LinkedList<Pair<P, V>>(); Iterator<P> pI = ps.iterator(); Iterator<V> vI = vs.iterator(); while (pI.hasNext()) { V nextV = (vI.hasNext() ? vI.next() : null); result.add(new Pair<P, V>(pI.next(), nextV)); } while (vI.hasNext()) { result.add(new Pair<P, V>(null, vI.next())); } return result; } /** * Unzips the given pair list by returning a list of the p values. * * @param * <P> * @param <V> * @param list * @return */ public static <P> List<P> pList(List<? extends Pair<P, ?>> list) { List<P> result = new LinkedList<P>(); for (Pair<P, ?> pair : list) { result.add(pair.p); } return result; } /** * Unzips the given pair by return a list of the v values. * * @param <V> * @param list * @return */ public static <V> List<V> vList(List<? extends Pair<?, V>> list) { List<V> result = new LinkedList<V>(); for (Pair<?, V> pair : list) { result.add(pair.v); } return result; } /** * Given an Iterator in Pair<P,V>, will return an Iterator in V that proxies all calls to the given iterator. */ public static <V> Iterator<V> iteratorV(final Iterator<? extends Pair<?, V>> iterator){ return new Iterator<V>(){ public boolean hasNext() { return iterator.hasNext(); } public V next() { return iterator.next().v; } public void remove() { iterator.remove(); } }; } /** * Given an iterable in Pair<P,V> will return an iterable in P. */ public static <V> Iterable<V> iterableV(final Iterable<? extends Pair<?, V>> iterable){ return new Iterable<V>(){ public Iterator<V> iterator() { return iteratorV(iterable.iterator()); } }; } /** * Given an Iterator in Pair<P,V>, will return an Iterator in P that proxies all calls to the given iterator. */ public static <P> Iterator<P> iteratorP(final Iterator<? extends Pair<P,?>> iterator){ return new Iterator<P>(){ public boolean hasNext() { return iterator.hasNext(); } public P next() { return iterator.next().p; } public void remove() { iterator.remove(); } }; } /** * Given an iterable in Pair<P,V> will return an iterable in P. */ public static <P> Iterable<P> iterableP(final Iterable<? extends Pair<P,?>> iterable){ return new Iterable<P>(){ public Iterator<P> iterator() { return iteratorP(iterable.iterator()); } }; } /** * Debugging Output method using the toString method of P and V. */ public String toString() { return new StringBuffer().append('<').append(p).append(',').append(v) .append('>').toString(); } @Override public int hashCode() { return (this.p == null ? 0 : this.p.hashCode()) | (this.v == null ? 0 : this.v.hashCode()); } /** * Returns true if both the p and v of the given pair equal p and v in the * current Pair. */ public boolean equals(Object o) { if (!(o instanceof Pair)) return false; Pair<?, ?> other = (Pair<?, ?>) o; return Util.equals(this.p, other.p) && Util.equals(this.v, other.v); } }