Thursday, May 31, 2012

What is the equivalent of the C++ Pair<L,R> in Java?


Is there a good reason why there is no Pair in Java? What would be the equivalent of this C++ construct? I would rather avoid reimplementing my own.



It seems that 1.6 is providing something similar (AbstractMap.SimpleEntry), but this looks quite convoluted.


Source: Tips4all

16 comments:

  1. In this thread on comp.lang.java.help, Hunter Gratzner gives some arguments against the presence of a Pair construct in Java. The main argument is that a class Pair doesn't convey any semantics about the relationship between the two values (how do you know what "first" and "second" mean ?).

    A better practice is to write a very simple class, like the one Mike proposed, for each application you would have made of the Pair class. Map.Entry is an example of a pair that carry its meaning in its name.

    To sum up, in my opinion it is better to have a class Position(x,y), a class Range(begin,end) and a class Entry(key,value) rather than a generic Pair(first,second) that doesn't tell me anything about what it's supposed to do.

    ReplyDelete
  2. HashMap compatible Pair class:

    public class Pair<A, B> {
    private A first;
    private B second;

    public Pair(A first, B second) {
    super();
    this.first = first;
    this.second = second;
    }

    public int hashCode() {
    int hashFirst = first != null ? first.hashCode() : 0;
    int hashSecond = second != null ? second.hashCode() : 0;

    return (hashFirst + hashSecond) * hashSecond + hashFirst;
    }

    public boolean equals(Object other) {
    if (other instanceof Pair) {
    Pair otherPair = (Pair) other;
    return
    (( this.first == otherPair.first ||
    ( this.first != null && otherPair.first != null &&
    this.first.equals(otherPair.first))) &&
    ( this.second == otherPair.second ||
    ( this.second != null && otherPair.second != null &&
    this.second.equals(otherPair.second))) );
    }

    return false;
    }

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

    public A getFirst() {
    return first;
    }

    public void setFirst(A first) {
    this.first = first;
    }

    public B getSecond() {
    return second;
    }

    public void setSecond(B second) {
    this.second = second;
    }
    }

    ReplyDelete
  3. This is Java. You have to make your own tailored Pair class with descriptive class and field names, and not to mind that you will reinvent the wheel by writing hashCode()/equals() or implementing Comparable again and again.

    ReplyDelete
  4. It depends on what you want to use it for. The typical reason to do so is to iterate over maps, for which you simply do this (Java 5+):

    Map<String, Object> map = ... ; // just an example
    for (Map.Entry<String, Object> entry : map.entrySet()) {
    System.out.printf("%s -> %s\n", entry.getKey(), entry.getValue());
    }

    ReplyDelete
  5. Another way to implement Pair with.


    Public immutable fields, i.e. simple data structure.
    Comparable.
    Simple hash and equals.
    Simple factory so you don't have to provide the types. e.g. Pair.of("hello", 1);

    public class Pair<FIRST, SECOND> implements Comparable<Pair<FIRST, SECOND>> {
    public final FIRST first;
    public final SECOND second;


    private Pair(FIRST first, SECOND second) {
    this.first = first;
    this.second = second;
    }


    public static <FIRST, SECOND> Pair<FIRST, SECOND> of(FIRST first, SECOND second) {
    return new Pair<FIRST, SECOND>(first, second);
    }


    @Override
    public int compareTo(Pair<FIRST, SECOND> o) {
    int cmp = compare(first, o.first);
    return cmp == 0 ? compare(second, o.second) : cmp;
    }
    // todo move this to a helper class.
    private static int compare(Object o1, Object o2) {
    return o1 == null ? o2 == null ? 0 : -1 : o2 == null ? +1 : ((Comparable) o1).compareTo(o2);
    }


    @Override
    public int hashCode() {
    return 31 * hashcode(first) + hashcode(second);
    }


    // todo move this to a helper class.
    private static int hashcode(Object o) {
    return o == null ? 0 : o.hashCode();
    }


    @Override
    public boolean equals(Object obj) {
    if (!(obj instanceof Pair)) return false;
    if (this == obj) return true;
    return equal(first, ((Pair) obj).first) && equal(second, ((Pair) obj).second);
    }


    // todo move this to a helper class.
    private boolean equal(Object o1, Object o2) {
    return o1 == null ? o2 == null : (o1 == o2 || o1.equals(o2));
    }


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

    ReplyDelete
  6. The shortest pair that I could come up with is the following, using Lombok:

    @Data
    @AllArgsConstructor(staticName = "of")
    public class Pair<F, S> {
    private F first;
    private S second;
    }


    It has all the benefits of the answer from @arturh (except the comparability), it has hashCode, equals, toString and a static “constructor”.

    ReplyDelete
  7. As many others have already stated, it really depends on the use case if a Pair class is useful or not.

    I think for a private helper function it is totally legitimate to use a Pair class if that makes your code more readable and is not worth the effort of creating yet another value class with all its boiler plate code.

    On the other hand, if your abstraction level requires you to clearly document the semantics of the class that contains two objects or values, then you should write a class for it. Usually that's the case if the data is a business object.

    As always, it requires skilled judgement.

    For your second question I recommend the Pair class from the Apache Commons libraries. Those might be considered as extended standard libraries for Java:

    http://commons.apache.org/lang/api-3.0-beta/org/apache/commons/lang3/Pair.html

    You might also want to have a look at Apache Commons' EqualsBuilder, HashCodeBuilder and ToStringBuilder which simplify writing value classes for your business objects.

    ReplyDelete
  8. How about http://www.javatuples.org/index.html I have found it very useful.

    The javatuples offers you tuple classes from one to ten elements:

    Unit<A> (1 element)
    Pair<A,B> (2 elements)
    Triplet<A,B,C> (3 elements)
    Quartet<A,B,C,D> (4 elements)
    Quintet<A,B,C,D,E> (5 elements)
    Sextet<A,B,C,D,E,F> (6 elements)
    Septet<A,B,C,D,E,F,G> (7 elements)
    Octet<A,B,C,D,E,F,G,H> (8 elements)
    Ennead<A,B,C,D,E,F,G,H,I> (9 elements)
    Decade<A,B,C,D,E,F,G,H,I,J> (10 elements)

    ReplyDelete
  9. The problem is that "pair" usually does not indicate very well what exactly the relationship between the two objects is.

    For instance, in a map in c++ you insert a pair to add a value, but you really are just saying you want to put a value in the map, which you later want to retrieve using a particular key. This key may or may not already exist in that map.

    Is there any particular reason you need a pair type?

    ReplyDelete
  10. Jakarta Commons Lang 3.0+ has a few Pair classes: http://commons.apache.org/lang/api/org/apache/commons/lang3/tuple/package-summary.html

    ReplyDelete
  11. Pair would be a good stuff, to be a basic construction unit for a complex generics, for instance, this is from my code:

    WeakHashMap<Pair<String, String>, String> map = ...


    It is just the same as Haskell's Tuple

    ReplyDelete
  12. Here's a Java Pair<> class I just now stole from Wikipedia here (so I can't vouch for how good it is):

    public class Pair<T, S>
    {
    public Pair(T f, S s)
    {
    first = f;
    second = s;
    }

    public T getFirst()
    {
    return first;
    }

    public S getSecond()
    {
    return second;
    }

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

    private T first;
    private S second;
    }

    ReplyDelete
  13. In my opinion, there is no Pair in Java because, if you want to add extra functionality directly on the pair (e.g. Comparable), you must bound the types. In C++, we just don't care, and if types composing a pair do not have operator <, the pair::operator < will not compile as well.

    An example of Comparable with no bounding:

    public class Pair<F, S> implements Comparable<Pair<? extends F, ? extends S>> {
    public final F first;
    public final S second;
    /* ... */
    public int compareTo(Pair<? extends F, ? extends S> that) {
    int cf = compare(first, that.first);
    return cf == 0 ? compare(second, that.second) : cf;
    }
    //Why null is decided to be less than everything?
    private static int compare(Object l, Object r) {
    if (l == null) {
    return r == null ? 0 : -1;
    } else {
    return r == null ? 1 : ((Comparable) (l)).compareTo(r);
    }
    }
    }

    /* ... */

    Pair<Thread, HashMap<String, Integer>> a = /* ... */;
    Pair<Thread, HashMap<String, Integer>> b = /* ... */;
    //Runtime error here instead of compile error!
    System.out.println(a.compareTo(b));


    An example of Comparable with compile-time check for whether type arguments are comparable:

    public class Pair<
    F extends Comparable<? super F>,
    S extends Comparable<? super S>
    > implements Comparable<Pair<? extends F, ? extends S>> {
    public final F first;
    public final S second;
    /* ... */
    public int compareTo(Pair<? extends F, ? extends S> that) {
    int cf = compare(first, that.first);
    return cf == 0 ? compare(second, that.second) : cf;
    }
    //Why null is decided to be less than everything?
    private static <
    T extends Comparable<? super T>
    > int compare(T l, T r) {
    if (l == null) {
    return r == null ? 0 : -1;
    } else {
    return r == null ? 1 : l.compareTo(r);
    }
    }
    }

    /* ... */

    //Will not compile because Thread is not Comparable<? super Thread>
    Pair<Thread, HashMap<String, Integer>> a = /* ... */;
    Pair<Thread, HashMap<String, Integer>> b = /* ... */;
    System.out.println(a.compareTo(b));


    This is good, but this time you may not use non-comparable types as type arguments in Pair.
    One may use lots of Comparators for Pair in some utility class, but C++ people may not get it. Another way is to write lots of classes in a type hierarchy with different bounds on type arguments, but there are too many possible bounds and their combinations...

    ReplyDelete
  14. Simple way Object [] - can be use as anу dimention tuple

    ReplyDelete