Using Pairs or 2-tuples in Java

JavaTuples

Java Problem Overview


My Hashtable in Java would benefit from a value having a tuple structure. What data structure can I use in Java to do that?

Hashtable<Long, Tuple<Set<Long>,Set<Long>>> table = ...

Java Solutions


Solution 1 - Java

I don't think there is a general purpose tuple class in Java but a custom one might be as easy as the following:

public class Tuple<X, Y> { 
  public final X x; 
  public final Y y; 
  public Tuple(X x, Y y) { 
    this.x = x; 
    this.y = y; 
  } 
} 

Of course, there are some important implications of how to design this class further regarding equality, immutability, etc., especially if you plan to use instances as keys for hashing.

Solution 2 - Java

javatuples is a dedicated project for tuples in Java.

Unit<A> (1 element)
Pair<A,B> (2 elements)
Triplet<A,B,C> (3 elements)

Solution 3 - Java

Apache Commons provided some common java utilities including a Pair. It implements Map.Entry, Comparable and Serializable.

Solution 4 - Java

If you are looking for a built-in Java two-element tuple, try AbstractMap.SimpleEntry.

Solution 5 - Java

As an extension to @maerics nice answer, I've added a few useful methods:

public class Tuple<X, Y> { 
	public final X x; 
	public final Y y; 
	public Tuple(X x, Y y) { 
		this.x = x; 
		this.y = y; 
	}
	
	@Override
	public String toString() {
		return "(" + x + "," + y + ")";
	}

	@Override
	public boolean equals(Object other) {
   	    if (other == this) {
	    	return true;
	    }

	    if (!(other instanceof Tuple)){
	    	return false;
	    }

	    Tuple<X,Y> other_ = (Tuple<X,Y>) other;

        // this may cause NPE if nulls are valid values for x or y. The logic may be improved to handle nulls properly, if needed.
	    return other_.x.equals(this.x) && other_.y.equals(this.y);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((x == null) ? 0 : x.hashCode());
		result = prime * result + ((y == null) ? 0 : y.hashCode());
		return result;
	}
}

Solution 6 - Java

Another 2 cents : Starting with Java 7, there is now a class for this in standard Lib : javafx.util.Pair.

And Yes, It is standard Java, now that JavaFx is included in the JDK :)

Solution 7 - Java

Here's this exact same question elsewhere, that includes a more robust equals, hash that maerics alludes to:

http://groups.google.com/group/comp.lang.java.help/browse_thread/thread/f8b63fc645c1b487/1d94be050cfc249b

That discussion goes on to mirror the maerics vs ColinD approaches of "should I re-use a class Tuple with an unspecific name, or make a new class with specific names each time I encounter this situation". Years ago I was in the latter camp; I've evolved into supporting the former.

Solution 8 - Java

With lombok it's easy to declare a Pair class:

@Data(staticConstructor = "of")
public class Pair<A, B> {
    private final A left;
    private final B right;
}

This will generates getters, static constructor named "of", equals(), hashcode() and toString().

see @Data documentation for more information

Solution 9 - Java

Android Tuple Utils

This object provides a sensible implementation of equals(), returning true if equals() is true on each of the contained objects.

Solution 10 - Java

Create a class that describes the concept you're actually modeling and use that. It can just store two Set<Long> and provide accessors for them, but it should be named to indicate what exactly each of those sets is and why they're grouped together.

Solution 11 - Java

To supplement @maerics's answer, here is the Comparable tuple:

import java.util.*;

/**
 * A tuple of two classes that implement Comparable
 */
public class ComparableTuple<X extends Comparable<? super X>, Y extends Comparable<? super Y>>
       extends Tuple<X, Y>
       implements Comparable<ComparableTuple<X, Y>>
{
  public ComparableTuple(X x, Y y) {
    super(x, y);
  }

  /**
   * Implements lexicographic order
   */
  public int compareTo(ComparableTuple<X, Y> other) {
    int d = this.x.compareTo(other.x);
    if (d == 0)
      return this.y.compareTo(other.y);
    return d;
  }
}

Solution 12 - Java

Though the article is pretty old now, and though I understand that I'm not really very helpful, I think the proposal described in Adding tuples to Java: a study in lightweight data structures, would have been nice in mainstream Java.

You can do things like:

int a;
char b;
float c;
[a,b,c] = [3,'a',2.33];

or

[int,int,char] x = [1,2,'a'];

or

public [int,boolean] Find(int i)
{
  int idx = FindInArray(A,i);
  return [idx,idx>=0];
}

[idx, found] = Find(7);

Here tuples are:

  • Defined as primitive types - no templates/generics
  • Stack-allocated if declared locally
  • Assigned using pattern-matching

This approach increases

  • Performance
  • Readability
  • Expressiveness

Solution 13 - Java

You can use Google Guava Table

Solution 14 - Java

I will start from a general point of view about tuples in Java and finish with an implication for your concrete problem.

  1. The way tuples are used in non-generic languages is avoided in Java because they are not type-safe (e.g. in Python: tuple = (4, 7.9, 'python')). If you still want to use something like a general purpose tuple (which is not recommended), you should use Object[] or List<Object> and cast the elements after a check with instanceof to assure type-safety.

Usually, tuples in a certain setting are always used the same way with containing the same structure. In Java, you have to define this structure explicitly in a class to provide well-defined, type-safe values and methods. This seems annoying and unnecessairy at first but prevents errors already at compile-time.

  1. If you need a tuple containing the same (super-)classes Foo, use Foo[], List<Foo>, or List<? extends Foo> (or the lists's immutable counterparts). Since a tuple is not of a defined length, this solution is equivalent.

  2. In your case, you seem to need a Pair (i.e. a tuple of well-defined length 2). This renders maerics's answer or one of the supplementary answers the most efficient since you can reuse the code in the future.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsykerView Question on Stackoverflow
Solution 1 - JavamaericsView Answer on Stackoverflow
Solution 2 - JavaDanielView Answer on Stackoverflow
Solution 3 - JavarhgbView Answer on Stackoverflow
Solution 4 - Javaat7000ftView Answer on Stackoverflow
Solution 5 - JavaAram KocharyanView Answer on Stackoverflow
Solution 6 - JavaTeocaliView Answer on Stackoverflow
Solution 7 - Javanot-just-yetiView Answer on Stackoverflow
Solution 8 - Javauser180100View Answer on Stackoverflow
Solution 9 - Javasee2851View Answer on Stackoverflow
Solution 10 - JavaColinDView Answer on Stackoverflow
Solution 11 - JavaAlexei AverchenkoView Answer on Stackoverflow
Solution 12 - JavaMads Boyd-MadsenView Answer on Stackoverflow
Solution 13 - JavaSteView Answer on Stackoverflow
Solution 14 - JavaMario ReutterView Answer on Stackoverflow