Using Pairs or 2-Tuples in Java

Using Pairs or 2-tuples in 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.

Does Java SE 8 have Pairs or Tuples?

UPDATE: This answer is in response to the original question, Does Java SE 8 have Pairs or Tuples? (And implicitly, if not, why not?) The OP has updated the question with a more complete example, but it seems like it can be solved without using any kind of Pair structure. [Note from OP: here is the other correct answer.]


The short answer is no. You either have to roll your own or bring in one of the several libraries that implements it.

Having a Pair class in Java SE was proposed and rejected at least once. See this discussion thread on one of the OpenJDK mailing lists. The tradeoffs are not obvious. On the one hand, there are many Pair implementations in other libraries and in application code. That demonstrates a need, and adding such a class to Java SE will increase reuse and sharing. On the other hand, having a Pair class adds to the temptation of creating complicated data structures out of Pairs and collections without creating the necessary types and abstractions. (That's a paraphrase of Kevin Bourillion's message from that thread.)

I recommend everybody read that entire email thread. It's remarkably insightful and has no flamage. It's quite convincing. When it started I thought, "Yeah, there should be a Pair class in Java SE" but by the time the thread reached its end I had changed my mind.

Note however that JavaFX has the javafx.util.Pair class. JavaFX's APIs evolved separately from the Java SE APIs.

As one can see from the linked question What is the equivalent of the C++ Pair in Java? there is quite a large design space surrounding what is apparently such a simple API. Should the objects be immutable? Should they be serializable? Should they be comparable? Should the class be final or not? Should the two elements be ordered? Should it be an interface or a class? Why stop at pairs? Why not triples, quads, or N-tuples?

And of course there is the inevitable naming bikeshed for the elements:

  • (a, b)
  • (first, second)
  • (left, right)
  • (car, cdr)
  • (foo, bar)
  • etc.

One big issue that has hardly been mentioned is the relationship of Pairs to primitives. If you have an (int x, int y) datum that represents a point in 2D space, representing this as Pair<Integer, Integer> consumes three objects instead of two 32-bit words. Furthermore, these objects must reside on the heap and will incur GC overhead.

It would seem clear that, like Streams, it would be essential for there to be primitive specializations for Pairs. Do we want to see:

Pair
ObjIntPair
ObjLongPair
ObjDoublePair
IntObjPair
IntIntPair
IntLongPair
IntDoublePair
LongObjPair
LongIntPair
LongLongPair
LongDoublePair
DoubleObjPair
DoubleIntPair
DoubleLongPair
DoubleDoublePair

Even an IntIntPair would still require one object on the heap.

These are, of course, reminiscent of the proliferation of functional interfaces in the java.util.function package in Java SE 8. If you don't want a bloated API, which ones would you leave out? You could also argue that this isn't enough, and that specializations for, say, Boolean should be added as well.

My feeling is that if Java had added a Pair class long ago, it would have been simple, or even simplistic, and it wouldn't have satisfied many of the use cases we are envisioning now. Consider that if Pair had been added in the JDK 1.0 time frame, it probably would have been mutable! (Look at java.util.Date.) Would people have been happy with that? My guess is that if there were a Pair class in Java, it would be kinda-sort-not-really-useful and everybody will still be rolling their own to satisfy their needs, there would be various Pair and Tuple implementations in external libraries, and people would still be arguing/discussing about how to fix Java's Pair class. In other words, kind of in the same place we're at today.

Meanwhile, some work is going on to address the fundamental issue, which is better support in the JVM (and eventually the Java language) for value types. See this State of the Values document. This is preliminary, speculative work, and it covers only issues from the JVM perspective, but it already has a fair amount of thought behind it. Of course there are no guarantees that this will get into Java 9, or ever get in anywhere, but it does show the current direction of thinking on this topic.

A Java collection of value pairs? (tuples?)

The Pair class is one of those "gimme" generics examples that is easy enough to write on your own. For example, off the top of my head:

public class Pair<L,R> {

private final L left;
private final R right;

public Pair(L left, R right) {
assert left != null;
assert right != null;

this.left = left;
this.right = right;
}

public L getLeft() { return left; }
public R getRight() { return right; }

@Override
public int hashCode() { return left.hashCode() ^ right.hashCode(); }

@Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) return false;
Pair pairo = (Pair) o;
return this.left.equals(pairo.getLeft()) &&
this.right.equals(pairo.getRight());
}

}

And yes, this exists in multiple places on the Net, with varying degrees of completeness and feature. (My example above is intended to be immutable.)

Creating a stream of multiple tuples out of one tuple pair

First you need to produce every pair from your set and easiest way I can think of right now

List<T> vals = new ArrayList(tupleSet);
Set<Tuple<T>> set = new HashSet();

for(int i = 0; i < vals.size() - 1; i++) {
for (int j = i+1; j < vals.size(); j++) {
set.add(new Tuple(vals.get(i), vals.get(j)));
}
}

Now for each tuple we need to generate permutations of its elements, since you have two elements in tuple only so there would be 4 permutations always.

You can find the algorithm to generate permutations online, you can store each permutation combination in tuple, so your one tuple generated above in for loop will generate 4 tuples

[(0,1), (1,2)] //we created this in for loop

This will produce using algorithm like this

[(0,0),(0,1),(1,1),(1,0),(1,1),(1,2),(2,1),(2,2)]

Now having this list, you can easily stream it using stream API function provided for every collection.

Edit: Since, here the requirement was to produce all pairs possible with 2 numbers, you didn't need the combinations logic (It was little unclear with question description), you can simply run two loops and produce all the tuples needed, something like this

public class TupelPairs<T> {
private TupleSet<T> tupleSet;
private final List<Tuple<T>> tuples;

public TupelPais(TupleSet<T> tupleSet) {
this.tupelSet = tupleSet;

// Convert your TupleSet<T> to some list here
// nums here is the List<T>, as I am not sure what is TupleSet here

tuples = new ArrayList<>();
// here we are generating tuple pairs
for(int i = 0; i < nums.size(); i++) {
for (T num : nums) {
tuples.add(new Tuple<T>(nums.get(i), num));
}
}
}


public Stream<Tupel<T>> getElements() {
return tuples.stream(); // Initialized in constructor
}
}

This would give output if suppose called with (assuming TupleSet some sort of set or list of T and T is Integer for example)

TuplePairs<Integer> pairs = new TuplePairs<Integer>(asList(1,2,3));

pairs.getElements(); // -> [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]

How to efficiently store a set of tuples/pairs in Java

Here are two possibilities.

One thing in both of the following suggestions is to store a bunch of pairs together as triple ints in an int[]. The first int would be the int and the next two ints would be the upper and lower half of the long.

If you didn't mind a 33% extra space disadvantage in exchange for an addressing speed advantage, you could use a long[] instead and store the int and long in separate indexes.

You'd never call an equals method. You'd just compare the three ints with three other ints, which would be very fast. You'd never call a compareTo method. You'd just do a custom lexicographic comparison of the three ints, which would be very fast.

B* tree

If memory usage is the ultimate concern, you can make a B* tree using an int[][] or an ArrayList<int[]>. B* trees are relatively quick and fairly compact.

There are also other types of B-trees that might be more appropriate to your particular use case.

Custom hash set

You can also implement a custom hash set with a custom, fast-calculated hash function (perhaps XOR the int and the upper and lower halves of the long together, which will be very fast) rather than relying on the hashCode method.

You'd have to figure out how to implement the int[] buckets to best suit the performance of your application. For example, how do you want to convert your custom hash code into a bucket number? Do you want to rebucket everything when the buckets start getting too many elements? And so on.

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

In a 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.

Java Tuple/Pair

As @Braj suggested, you can use a for-each loop.

for(Pair<Integer, String> p : test ){
System.out.println(p.getT());
}

However, because of the way you are adding objects, the output will actually be:

B
B

This is because when you add an object to the ArrayList, you are actually adding a reference to that object, so when you modify it, you will modify the one stored in the ArrayList as well. A separate copy of the object is not created! You need to construct a new Pair object for this to work as you intend.

Another note: you haven't used a constructor to initialize pair, so javac will yell at you.

To get around both of theses errors, change your code to this:

List<Pair<Integer, String>> test = new ArrayList<Pair<Integer, String>>();
test.add(new Pair<Integer, String>(1, "A"));
test.add(new Pair<Integer, String>(2, "B"));
for(Pair<Integer, String> p : test ){
System.out.println(p.getT());
}


Related Topics



Leave a reply



Submit