我需要从3个整数到对象的唯一映射。我不能对这些整数的值做任何假设,除了它们是积极的。
我目前使用这样的hashmap实现它:
int a = 10;
int b = 20;
int c = 30;
Map<String, MyObject> map = new HashMap<>();
map.put(a + "_" + b + "_" + c, myObject);
虽然这有效,但看起来有点难看。
有没有更好的选择,没有引入冲突,没有使用第三方库?
编辑:我刚刚意识到我实际上可以对我的整数做出更具体的假设。它们的重量都在1,000,000到2,000,000之间,它们的重量在底部,因为它们的序列开始计数为1,000,000。答案 0 :(得分:3)
final class Key{
int a , b , c;
public Key(int a , int b , int c){
this.a = a;
this.b = b;
this.c = c;
}
public int hashCode(){
return (a << 10 ^ b << 5 ^ c);
}
public boolean equals(Object o){
if(!(o instanceof Key))
return false;
Key k = (Key) o;
return (k.a == a && k.b == b && k.c == c);
}
}
这甚至可以用于负值。
答案 1 :(得分:3)
你可以像这样创建一个Key
类:
final class Key {
final int a;
final int b;
final int c;
Key(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Key)) {
return false;
}
Key that = (Key) obj;
return (this.a == that.a)
&& (this.b == that.b)
&& (this.c == that.c);
}
@Override
public int hashCode() {
return Objects.hash(this.a, this.b, this.c);
}
}
将地图设为Map<Key, MyObject>
。
使用String
的优点之一是类型安全。你无法做到这一点,例如:
map.put("Some arbitrary string that has nothing to do with numbers", myObject);
答案 2 :(得分:1)
因为每个值的范围最多有2M个不同的连续值,低于2 21 值,并且有3个这样的值,所以不同组合的数量低于2 63 。这些组合巧妙地(恰好)适合long
值的范围(2 64 ),因此使用正确的数学,a,b和c的每个唯一组合都可以有自己的{{ 1}}值。
这是一个简洁且高性能的工具,它使用位操作来完成工作:
long
如果您制作地图的密钥类型// safe for a, b and c in range 0-2,097,151 (21 bits)
private static long key(long a, long b, long c) {
return a << 42 | b << 21 | c;
}
,则可以使用此方法的结果作为密钥:
Long
我还没有测量Map<Long, MyObject> map = new HashMap<>();
map.put(key(a, b, c), myObject);
方法的性能,但它只有几个CPU周期。
答案 3 :(得分:0)
像某些答案所指出的那样,拥有自己的密钥类会起作用。像往常一样,使用哈希码和等号检测冲突。
就个人而言,我喜欢无限数量的整体选项,以提高灵活性。
public final class IntArrayKey{
private final List<Integer> values = new ArrayList<>();
private final int hash;
private final String stringValue;
public IntArrayKey(Integer ...ints){
values.addAll(Arrays.asList(ints));
hash = Arrays.hashCode(ints);
stringValue = values.toString();
}
@Override
public boolean equals(Object o){
if(o == this) return true;
if(!(o instanceof IntArrayKey)) return false;
return values.equals(((IntArrayKey) o).values);
}
@Override
public int hashCode(){
return hash;
}
@Override
public String toString(){
return stringValue;
}
}