如何通过以二维int数组为键的HashMap搜索

时间:2019-02-04 20:40:13

标签: java

我有很多二维整数数组(大小为8x8),每个二维整数数组都基于计算得出一些数值双精度值。我想将它们存储在数据结构中,这样就可以查找一个二维数组,并检查我之前给该数组指定的值。

我一直在尝试使用二维数组的hashCode,但是没有用。 我还尝试了将数组作为键的hashMap,并尝试创建自定义对象作为键。但是都没有为我解决,所以我做错了。在哪里找到解决方案?

3 个答案:

答案 0 :(得分:1)

由于Java数组不会覆盖hashCode()本机实现中的euqals()Object,因此它们实际上不适合查找。例如,两个相同的数组不相等:

int[][] a1 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int[][] a2 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
System.out.println(a1.hashCode()); // 1277181601
System.out.println(a2.hashCode()); // 41903949
System.out.println(a1.equals(a2)); // false

但是,可以创建一个内部使用Arrays.deepHashCode()Arrays.deepEquals()的包装器类,如下所示:

public class IntIntArray {
  private int[][] values;

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    IntIntArray that = (IntIntArray) o;
    return Arrays.deepEquals(value, that.value);
  }

  @Override
  public int hashCode() {
    return Arrays.deepHashCode(value);
  }
}

此类适用于基于值的查找,并且可以用作Map键:

IntIntArray i1 = new IntIntArray(new int[][] {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
IntIntArray i2 = new IntIntArray(new int[][] {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
System.out.println(i1.hashCode()); // 30729379
System.out.println(i2.hashCode()); // 30729379
System.out.println(i1.equals(i2)); // true

答案 1 :(得分:0)

如果您使用的是数组的 SAME INSTANCE ,则可以不做任何事情就将它们用作键:

@Test
public void test1() {
    Integer[][] arr = new Integer[8][];

    for (int i = 1; i <= 8; i++) {
        arr[i-1] = new Integer[] {545*i,237*i,3513*i,461*i,465*i,20*i,134*i,352*i};
    }

    Map<Integer[][], Double> map = new HashMap<>();
    map.put(arr, 5.7);
    Double val = map.get(arr);

    assert val == 5.7;
}

您可以在此处看到,使用与放置该值相同的数组从地图中获取该值将返回所需的值。

这是因为哈希码和equals数组的实现是检查同一实例,如果您的情况也是如此,那么性能也很好。

但是,如果您具有同一数组(键)的不同实例,则将无法使用:

@Test
public void test2() {
    Integer[][] arr1 = new Integer[8][];
    Integer[][] arr2 = new Integer[8][];

    for (int i = 1; i <= 8; i++) {
        arr1[i-1] = new Integer[] {545*i,237*i,3513*i,461*i,465*i,20*i,134*i,352*i};
        arr2[i-1] = new Integer[] {545*i,237*i,3513*i,461*i,465*i,20*i,134*i,352*i};
    }

    Map<Integer[][], Double> map = new HashMap<>();
    map.put(arr1, 5.7);
    Double val = map.get(arr2);

    assert val == null;
}

相反,您需要创建一个“ Key”对象并为其实现equals和哈希代码:

class MyKey {
    Integer[][] arr;

    public MyKey(Integer[][] arr) {
        this.arr = arr;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyKey myKey = (MyKey) o;
        return Arrays.deepEquals(arr, myKey.arr);
    }

    @Override
    public int hashCode() {
        return Arrays.deepHashCode(arr);
    }
}

并使用它:

@Test
public void test2() {
    Integer[][] arr1 = new Integer[8][];
    Integer[][] arr2 = new Integer[8][];

    for (int i = 1; i <= 8; i++) {
        arr1[i-1] = new Integer[] {545*i,237*i,3513*i,461*i,465*i,20*i,134*i,352*i};
        arr2[i-1] = new Integer[] {545*i,237*i,3513*i,461*i,465*i,20*i,134*i,352*i};
    }

    Map<MyKey, Double> map = new HashMap<>();
    map.put(new MyKey(arr1), 5.7);
    Double val = map.get(new MyKey(arr2));

    assert val == 5.7;
}

答案 2 :(得分:-1)

使用List<List<Integer>>而不是使用数组,并使用具有hashCode作为键的映射。根据{{​​3}},如果列表中的值相同,则每次都应获得相同的值。 hashCode通过以下方式计算。

int hashCode = 1;
  Iterator<E> i = list.iterator();
  while (i.hasNext()) {
      E obj = i.next();
      hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
  }

它也提到了

  

这确保list1.equals(list2)暗示   list1.hashCode()==list2.hashCode()用于list1list2这两个列表,   根据{{​​1}}的总合同的要求。