Using Pairs or 2-tuples in Java [duplicate]
My Hashtable in Java would benefit from a value having a tuple structure. What data structure can I use in Java to do that?
Hashta开发者_开发知识库ble<Long, Tuple<Set<Long>,Set<Long>>> table = ...
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.
javatuples is a dedicated project for tuples in Java.
Unit<A> (1 element)
Pair<A,B> (2 elements)
Triplet<A,B,C> (3 elements)
Apache Commons provided some common java utilities including a Pair. It implements Map.Entry
, Comparable
and Serializable
.
If you are looking for a built-in Java two-element tuple, try AbstractMap.SimpleEntry
.
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;
}
}
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 :)
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.
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
Android Tuple Utils
This object provides a sensible implementation of equals(), returning true if equals() is true on each of the contained objects.
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.
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
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;
}
}
You can use Google Guava Table
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.
2) 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.
3) 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.
精彩评论