我有两个数字,我想一起使用它们作为一个关键Map
。 目前,我在他们的串联字符串表示。 例如,假设键号码4和12使用:
String key = 4 + "," + 12;
地图被声明为Map<String, Object>
。
我觉得这是如此糟糕! 我喜欢用比其他一些String
作为关键! 我要创建这些键的最快方式。
谁拥有一个好主意?
我有两个数字,我想一起使用它们作为一个关键Map
。 目前,我在他们的串联字符串表示。 例如,假设键号码4和12使用:
String key = 4 + "," + 12;
地图被声明为Map<String, Object>
。
我觉得这是如此糟糕! 我喜欢用比其他一些String
作为关键! 我要创建这些键的最快方式。
谁拥有一个好主意?
创建包含两个数字的对象,并将其作为重点。 例如:
class Coordinates {
private int x;
private int y;
public Coordinates(int x, int y) {
...
}
// getters
// equals and hashcode using x and y
}
Map<Coordinates, Location> locations = new HashMap<Coordinates, Location>();
如果你喜欢数学方法,请参阅该StackOverflow的答案 。
您应该使用java.awt.Dimension中为你的关键。
尺寸键=新尺寸(4,12);
维具有产生针对每对正整数的一个不同的hashCode,以便为(4,12)和所述散列码(12,4)是不同的一个非常好的hashcode()方法。 因此,这些都是快速实例化并取得很好的哈希码。
我真希望他们所取得的类不可变的,但你可以让自己的不可变类的维度建模。
以下是表示用于宽度和高度的不同值哈希码的表:
0 1 2 3 4 <-- width
+--------------------
0 | 0 2 5 9 14
1 | 1 4 8 13
2 | 3 7 12
3 | 6 11
4 | 10
^
|
height
如果您按照散列码,以便从0到14,你会看到的模式。
下面是产生这种的hashCode的代码:
public int hashCode() {
int sum = width + height;
return sum * (sum + 1)/2 + width;
}
你可能认识到最后一行中的三角形数量的公式。 这就是为什么该表的第一列包含了所有的三角形数量。
对于速度,您应该计算在构造函数中的hashCode。 所以全班看起来是这样的:
public class PairHash {
private final int hash;
public PairHash(int a, int b) {
int sum = a+b;
hash = sum * (sum+1)/2 + a;
}
public int hashCode() { return hash; }
}
当然,如果你可能需要一个equals方法,但你自己限制在一个不会溢出正整数,你可以添加一个非常快的一个:
public class PairHash {
// PAIR_LIMIT is 23170
// Keeping the inputs below this level prevents overflow, and guarantees
// the hash will be unique for each pair of positive integers. This
// lets you use the hashCode in the equals method.
public static final int PAIR_LIMIT = (int) (Math.sqrt(Integer.MAX_VALUE))/2;
private final int hash;
public PairHash(int a, int b) {
assert a >= 0;
assert b >= 0;
assert a < PAIR_LIMIT;
assert b < PAIR_LIMIT;
int sum = a + b;
hash = sum * (sum + 1) / 2 + a;
}
public int hashCode() { return hash; }
public boolean equals(Object other) {
if (other instanceof PairHash){
return hash == ((PairHash) other).hash;
}
return false;
}
}
我们限制此为正值,因为负值会产生一些重复的哈希码。 但随着这一限制,这些都是最快的hashCode()和equals()方法可以写入。 (当然,你可以通过在构造函数计算的hashCode写哈希码只在任何不可变类一样快。)
如果你不能与那些限制生活,你只需要保存参数。
public class PairHash {
private final int a, b, hash;
public PairHash(int a, int b) {
this.a = a;
this.b = b;
int sum = a+b;
hash = sum * (sum+1)/2 + a;
}
public int hashCode() { return hash; }
public boolean equals(Object other) {
if (other instanceof PairHash) {
PairHash otherPair = (PairHash)other;
return a == otherPair.a && b == otherPair.b;
}
return false;
}
但这里的踢球。 你不需要这个类的。 由于公式为您提供的每一对数字的唯一整数,你可以只使用整数作为地图的关键。 Integer类都有自己的快速equals()和hashCode方法,将工作的罚款。 这种方法将产生两个短值的哈希键。 该限制是你的输入必须是积极的短值。 这是保证不会溢出,并通过浇铸中间和一个长,它有一个较宽的范围比前面的方法:它适用于所有正短的值。
static int hashKeyFromPair(short a, short b) {
assert a >= 0;
assert b >= 0;
long sum = (long) a + (long) b;
return (int) (sum * (sum + 1) / 2) + a;
}
如果与对象的解决方案去, 请确保您的关键对象是不可改变的 。
否则,如果某人变异的值,不仅会不再是等于其他明显相同的值,但存储在地图的哈希码将不再匹配由返回的一个hashCode()
方法。 在这一点上你基本上SOL。
例如,使用java.awt.Point
-这看起来,在纸面上,就像你想要什么-以下内容:
public static void main(String[] args) {
Map<Point, Object> map = new HashMap<Point, Object>();
Point key = new Point(1, 3);
Object val = new Object();
map.put(key, val);
System.out.println(map.containsKey(key));
System.out.println(map.containsKey(new Point(1, 3)));
// equivalent to setLeft() / setRight() in ZZCoder's solution,
// or setX() / setY() in SingleShot's
key.setLocation(2, 4);
System.out.println(map.containsKey(key));
System.out.println(map.containsKey(new Point(2, 4)));
System.out.println(map.containsKey(new Point(1, 3)));
}
打印:
true
true
false
false
false
你可以存储两个整数在相当长的这个样子,
long n = (l << 32) | (r & 0XFFFFFFFFL);
或者你可以使用下面Pair<Integer, Integer>
类,
public class Pair<L, R> {
private L l;
private R r;
public Pair() {
}
public Pair(L l, R r) {
this.l = l;
this.r = r;
}
public L getLeft() {
return l;
}
public R getRight() {
return r;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) {
return false;
}
Pair obj = (Pair) o;
return l.equals(obj.l) && r.equals(obj.r);
}
@Override
public int hashCode() {
return l.hashCode() ^ r.hashCode();
}
}
一个实际的回答这个问题是:
hashCode = a + b * 17;
...其中a,b和hashCode都是整数。 17只是一个任意的素数。 你哈希不会是唯一的,不过没关系。 这种事情是各地使用Java标准库。
另一种方法是使用嵌套的地图:
Map<Integer,Map<Integer,Object>>
在这里,你有没有开销创建密钥。 然而,你有更多的开销来正确地创建和检索条目,你总是需要来图来访问找到你正在寻找的对象。
为什么要编写所有额外的代码,使一个完全成熟的类,你不需要为别的比使用一个简单的字符串比较好? 将计算的哈希代码该类的实例是比字符串快多少? 我不认为如此。
除非你是在一个非常有限的计算能力的环境中运行,使得和散列字符串不应该明显高于实例自定义类的大的开销。
我想以最快的方式是简单地在整数打包成一个单一的龙象ZZ编码器的建议,但在任何情况下,我不认为速度的收益是巨大的。
你需要写正确eqauls和hashCode方法,或者产生一些错误。