如何使用两个键(Key-Pair,Value)创建HashMap?

Cro*_*ode 114 java hash hashmap hashcode

我有一个整数的2D数组.我希望将它们放入HashMap中.但我想基于Array Index访问HashMap中的元素.就像是:

对于A [2] [5],map.get(2,5)它返回与该键相关联的值.但是如何使用一对键创建hashMap?或者一般来说,多个键:Map<((key1, key2,..,keyN), Value)我可以使用get(key1,key2,... keyN)访问元素.

编辑:发布问题3年后,我想补充一点

我遇到了另一种方式NxN matrix.

数组索引,ij可被表示为一个单一的key方式如下:

int key = i * N + j;
//map.put(key, a[i][j]); // queue.add(key); 
Run Code Online (Sandbox Code Playgroud)

并且可以通过key以下方式从这些指数中恢复指数:

int i = key / N;
int j = key % N;
Run Code Online (Sandbox Code Playgroud)

Tom*_*icz 184

有几种选择:

2个维度

地图地图

Map<Integer, Map<Integer, V>> map = //...
//...

map.get(2).get(5);
Run Code Online (Sandbox Code Playgroud)

包装密钥对象

public class Key {

    private final int x;
    private final int y;

    public Key(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Key)) return false;
        Key key = (Key) o;
        return x == key.x && y == key.y;
    }

    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }

}
Run Code Online (Sandbox Code Playgroud)

实施equals()hashCode()在这里至关重要.然后你只需使用:

Map<Key, V> map = //...
Run Code Online (Sandbox Code Playgroud)

和:

map.get(new Key(2, 5));
Run Code Online (Sandbox Code Playgroud)

Table 来自番石榴

Table<Integer, Integer, V> table = HashBasedTable.create();
//...

table.get(2, 5);
Run Code Online (Sandbox Code Playgroud)

Table使用下面的地图.

N维

请注意,特殊Key类是唯一可扩展到n维的方法.您可能还会考虑:

Map<List<Integer>, V> map = //...
Run Code Online (Sandbox Code Playgroud)

但从性能角度来看,这是可怕的,以及可读性和正确性(没有简单的方法来强制列表大小).

也许看看Scala,你有元组和case类(用Key一行代替整个班级).

  • 嗨,其他人在做hashCode时有x'或两个值.你为什么用31?我认为这与32位整数有关,但是当我想到它时没有意义,因为x = 1和y = 0仍然映射到相同的哈希码,因为x = 0和y = 31 (3认同)
  • 为什么不使用Map.Entry &lt;K,V&gt;作为键,而不是Wrapper键对象? (2认同)
  • `Map&lt;Pair&lt;Key1, Key2&gt;, Value&gt;` 怎么样? (2认同)

chr*_*xle 22

当您创建自己的密钥对对象时,您应该面对一些事情.

首先,您应该了解实施hashCode()equals().你需要这样做.

其次,在实施时hashCode(),请确保您了解其工作原理.给定的用户示例

public int hashCode() {
    return this.x ^ this.y;
}
Run Code Online (Sandbox Code Playgroud)

实际上是你可以做的最糟糕的实现之一.原因很简单:你有很多平等的哈希!并且hashCode()应该返回往往很少见的int值,这是最好的唯一值.使用这样的东西:

public int hashCode() {
  return (X << 16) + Y;
}
Run Code Online (Sandbox Code Playgroud)

这很快并且返回-2 ^ 16和2 ^ 16-1(-65536到65535)之间的键的唯一哈希值.几乎适用于任何情况.很少有人超出这个范围.

第三,实现时equals()也知道它的用途,并了解如何创建密钥,因为它们是对象.通常你会做不必要的if语句,因为你总是会得到相同的结果.

如果您创建这样的键:map.put(new Key(x,y),V);您永远不会比较键的引用.因为每次你想访问地图,你会做类似的事情map.get(new Key(x,y));.因此,您equals()不需要像这样的声明if (this == obj).它永远不会发生.

而不是if (getClass() != obj.getClass())在你equals()更好的使用if (!(obj instanceof this)).它甚至对子类也有效.

所以你唯一需要比较的就是X和Y.所以equals()在这种情况下最好的实现是:

public boolean equals (final Object O) {
  if (!(O instanceof Key)) return false;
  if (((Key) O).X != X) return false;
  if (((Key) O).Y != Y) return false;
  return true;
}
Run Code Online (Sandbox Code Playgroud)

所以最后你的关键类是这样的:

public class Key {

  public final int X;
  public final int Y;

  public Key(final int X, final int Y) {
    this.X = X;
    this.Y = Y;
  }

  public boolean equals (final Object O) {
    if (!(O instanceof Key)) return false;
    if (((Key) O).X != X) return false;
    if (((Key) O).Y != Y) return false;
    return true;
  }

  public int hashCode() {
    return (X << 16) + Y;
  }

}
Run Code Online (Sandbox Code Playgroud)

您可以提供维度索引XY公共访问级别,因为它们是最终的并且不包含敏感信息.在转换为a 时,我不能100%确定private访问级别是否在任何情况下都能正常工作.ObjectKey

如果你对决赛感到好奇,我会宣布任何事情都是最终的,在实例化时设置的值并且永远不会改变 - 因此它是一个对象常量.


Bra*_*rad 6

您不能拥有包含多个键的哈希映射,但您可以拥有一个以多个参数作为键的对象.

创建一个名为Index的对象,该对象采用x和y值.

public class Index {

    private int x;
    private int y;

    public Index(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        return this.x ^ this.y;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Index other = (Index) obj;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后让你HashMap<Index, Value>得到你的结果.:)

  • 你需要覆盖`hashCode`和`equals`. (4认同)
  • hashCode实现没有区分(2,1)和(1,2) (4认同)

Raj*_*hah 6

Java 7+ 包含一个新Map.Entry<K,V>类,您可以将其用作地图的键(或集合的条目)。Java 9+ 还包含一种Map.entry(K k, V v)轻松创建新Map.Entry对象的方法。

用法:

Map<Map.Entry<Integer,Integer>, Integer> map = new HashMap<>();
map.put(Map.entry(1, 2), 0);
Run Code Online (Sandbox Code Playgroud)

Pair<K, V>javafx.util中也有

Map<Pair<Integer,Integer>, Integer> map = new HashMap<>();
map.put(new Pair(1, 2), 0);
Run Code Online (Sandbox Code Playgroud)


Cyr*_* Ka 5

两种可能性。使用组合键:

class MyKey {
    int firstIndex;
    int secondIndex;
    // important: override hashCode() and equals()
}
Run Code Online (Sandbox Code Playgroud)

或者地图的地图:

Map<Integer, Map<Integer, Integer>> myMap;
Run Code Online (Sandbox Code Playgroud)

  • 仅当您不关心此处的性能或内存使用(即映射很小),或者有许多具有相同第一个索引的键时,才使用映射的映射 - 因为此解决方案意味着支付 HashMap 对象的开销每个唯一的第一个索引。 (3认同)

MrS*_*h42 5

使用 aPair作为 的键HashMap。JDK 没有 Pair,但您可以使用第三方库(例如http://commons.apache.org/lang)或编写自己的 Pair 类型。