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

edu.stanford.nlp.util.Pair Maven / Gradle / Ivy

package edu.stanford.nlp.util;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.Serializable;
import java.util.Comparator;
import java.util.List;

import edu.stanford.nlp.util.logging.PrettyLoggable;
import edu.stanford.nlp.util.logging.PrettyLogger;
import edu.stanford.nlp.util.logging.Redwood.RedwoodChannels;

/**
 * Pair is a Class for holding mutable pairs of objects.
 *
 * Implementation note:
 * on a 32-bit JVM uses ~ 8 (this) + 4 (first) + 4 (second) = 16 bytes.
 * on a 64-bit JVM uses ~ 16 (this) + 8 (first) + 8 (second) = 32 bytes.
 *
 * Many applications use a lot of Pairs so it's good to keep this
 * number small.
 *
 * @author Dan Klein
 * @author Christopher Manning (added stuff from Kristina's, rounded out)
 * @version 2002/08/25
 */

public class Pair  implements Comparable>, Serializable, PrettyLoggable {

  /**
   * Direct access is deprecated.  Use first().
   *
   * @serial
   */
  public T1 first;

  /**
   * Direct access is deprecated.  Use second().
   *
   * @serial
   */
  public T2 second;

  public Pair() {
    // first = null; second = null; -- default initialization
  }

  public Pair(T1 first, T2 second) {
    this.first = first;
    this.second = second;
  }

  public T1 first() {
    return first;
  }

  public T2 second() {
    return second;
  }

  public void setFirst(T1 o) {
    first = o;
  }

  public void setSecond(T2 o) {
    second = o;
  }

  @Override
  public String toString() {
    return "(" + first + "," + second + ")";
  }

  @Override
  public boolean equals(Object o) {
    if (o instanceof Pair) {
      @SuppressWarnings("rawtypes")
      Pair p = (Pair) o;
      return (first == null ? p.first() == null : first.equals(p.first())) && (second == null ? p.second() == null : second.equals(p.second()));
    } else {
      return false;
    }
  }

  @Override
  public int hashCode() {
    int firstHash  = (first == null ? 0 : first.hashCode());
    int secondHash = (second == null ? 0 : second.hashCode());

    return firstHash*31 + secondHash;
  }

  public List asList() {
    return CollectionUtils.makeList(first, second);
  }

  /**
   * Read a string representation of a Pair from a DataStream.
   * This might not work correctly unless the pair of objects are of type
   * String.
   */
  public static Pair readStringPair(DataInputStream in) {
    Pair p = new Pair<>();
    try {
      p.first = in.readUTF();
      p.second = in.readUTF();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return p;
  }

  /**
   * Returns a Pair constructed from X and Y.  Convenience method; the
   * compiler will disambiguate the classes used for you so that you
   * don't have to write out potentially long class names.
   */
  public static  Pair makePair(X x, Y y) {
    return new Pair<>(x, y);
  }

  /**
   * Write a string representation of a Pair to a DataStream.
   * The toString() method is called on each of the pair
   * of objects and a String representation is written.
   * This might not allow one to recover the pair of objects unless they
   * are of type String.
   */
  public void save(DataOutputStream out) {
    try {
      out.writeUTF(first.toString());
      out.writeUTF(second.toString());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Compares this Pair to another object.
   * If the object is a Pair, this function will work providing
   * the elements of the Pair are themselves comparable.
   * It will then return a value based on the pair of objects, where
   * p > q iff p.first() > q.first() ||
   * (p.first().equals(q.first()) && p.second() > q.second()).
   * If the other object is not a Pair, it throws a
   * ClassCastException.
   *
   * @param another the Object to be compared.
   * @return the value 0 if the argument is a
   *         Pair equal to this Pair; a value less than
   *         0 if the argument is a Pair
   *         greater than this Pair; and a value
   *         greater than 0 if the argument is a
   *         Pair less than this Pair.
   * @throws ClassCastException if the argument is not a
   *                            Pair.
   * @see java.lang.Comparable
   */
  @SuppressWarnings("unchecked")
  public int compareTo(Pair another) {
    if (first() instanceof Comparable) {
      int comp = ((Comparable) first()).compareTo(another.first());
      if (comp != 0) {
        return comp;
      }
    }

    if (second() instanceof Comparable) {
      return ((Comparable) second()).compareTo(another.second());
    }

    if ((!(first() instanceof Comparable)) && (!(second() instanceof Comparable))) {
      throw new AssertionError("Neither element of pair comparable");
    }

    return 0;
  }

  /**
   * If first and second are Strings, then this returns an MutableInternedPair
   * where the Strings have been interned, and if this Pair is serialized
   * and then deserialized, first and second are interned upon
   * deserialization.
   *
   * @param p A pair of Strings
   * @return MutableInternedPair, with same first and second as this.
   */
  public static Pair stringIntern(Pair p) {
    return new MutableInternedPair(p);
  }

  /**
   * Returns an MutableInternedPair where the Strings have been interned.
   * This is a factory method for creating an
   * MutableInternedPair.  It requires the arguments to be Strings.
   * If this Pair is serialized
   * and then deserialized, first and second are interned upon
   * deserialization.
   * 

Note: I put this in thinking that its use might be * faster than calling x = new Pair(a, b).stringIntern() * but it's not really clear whether this is true. * * @param first The first object * @param second The second object * @return An MutableInternedPair, with given first and second */ public static Pair internedStringPair(String first, String second) { return new MutableInternedPair(first, second); } /** * use serialVersionUID for cross version serialization compatibility */ private static final long serialVersionUID = 1360822168806852921L; static class MutableInternedPair extends Pair { private MutableInternedPair(Pair p) { super(p.first, p.second); internStrings(); } private MutableInternedPair(String first, String second) { super(first, second); internStrings(); } protected Object readResolve() { internStrings(); return this; } private void internStrings() { if (first != null) { first = first.intern(); } if (second != null) { second = second.intern(); } } // use serialVersionUID for cross version serialization compatibility private static final long serialVersionUID = 1360822168806852922L; } /** * {@inheritDoc} */ public void prettyLog(RedwoodChannels channels, String description) { PrettyLogger.log(channels, description, this.asList()); } /** * Compares a Pair to another Pair according to the first object of the pair only * This function will work providing * the first element of the Pair is comparable, otherwise will throw a * ClassCastException * @author jonathanberant * * @param * @param */ public static class ByFirstPairComparator implements Comparator> { @SuppressWarnings("unchecked") @Override public int compare(Pair pair1, Pair pair2) { return ((Comparable) pair1.first()).compareTo(pair2.first()); } } /** * Compares a Pair to another Pair according to the first object of the pair only in decreasing order * This function will work providing * the first element of the Pair is comparable, otherwise will throw a * ClassCastException * @author jonathanberant * * @param * @param */ public static class ByFirstReversePairComparator implements Comparator> { @SuppressWarnings("unchecked") @Override public int compare(Pair pair1, Pair pair2) { return -((Comparable) pair1.first()).compareTo(pair2.first()); } } /** * Compares a Pair to another Pair according to the second object of the pair only * This function will work providing * the first element of the Pair is comparable, otherwise will throw a * ClassCastException * @author jonathanberant * * @param * @param */ public static class BySecondPairComparator implements Comparator> { @SuppressWarnings("unchecked") @Override public int compare(Pair pair1, Pair pair2) { return ((Comparable) pair1.second()).compareTo(pair2.second()); } } /** * Compares a Pair to another Pair according to the second object of the pair only in decreasing order * This function will work providing * the first element of the Pair is comparable, otherwise will throw a * ClassCastException * @author jonathanberant * * @param * @param */ public static class BySecondReversePairComparator implements Comparator> { @SuppressWarnings("unchecked") @Override public int compare(Pair pair1, Pair pair2) { return -((Comparable) pair1.second()).compareTo(pair2.second()); } } }