【问题标题】:Using an array as a hash key in Java?在Java中使用数组作为哈希键?
【发布时间】:2015-04-24 05:46:28
【问题描述】:

我有一个函数可以进行一些计算。它接受一个 int 数组并根据传递给它的 int 数组的内容返回一个整数。

由于我的应用程序正在执行数百个此类计算,因此我正在尝试设置一种将这些计算结果存储在哈希图中的方法,这样它就不必重新计算它最近已经进行的计算。为此,我需要使用 int 数组作为哈希图的键。

目前这是打印尺寸 2,我希望它打印尺寸 1:

LinkedHashMap hashmap = new LinkedHashMap();

int test[] = {1,2,3};
int test2[] = {1,2,3};

hashmap.put(test, 1);
hashmap.put(test2, 1);

System.out.println("Size: "+hashmap.size());

实现这一目标的最佳方法是什么?我可以创建一种方法来将数组转换为某种对数组数据进行编码的字符串,但我认为这不是最好的解决方案。

【问题讨论】:

  • 您可以将Lists 存储在哈希图中。
  • 您可以使用任何对象作为哈希图的键,为了您的目的,您可以使用 List 而不是使用 int 数组
  • List 或将数组包装在一个简单的类中,该类覆盖 equals()/hashCode();查看Arrays 类
  • 你应该看看 Trove 库。它支持原始集合、映射和自定义散列策略。
  • 大家对 hashset 有什么看法?

标签: java hashmap


【解决方案1】:

当前打印的是 2,因为它们是具有两个不同 hashCode 的两个不同数组,因此尽管它们具有相同的元素,但对于集合而言它们是不同的。您应该创建自己的对象,该对象具有一个数组作为对象内部的变量。然后它会覆盖equals和hashCode方法,使得值根据数组中的值是相同的。

例如:

 public class MyClass
 {
        private int[] array;

       public boolean equals(Object o)
       {
           if(! (o instance of MyClass) ) return false;
           //loop through the arrays to see they are equal
         }

        public int hashCode()
       {  
           //loop through the array and return a number that is based off of the values in the array such as array[0] ^ array[1] + array[2] * array[3] / array[4] ...

        }
 }

【讨论】:

  • 您可以将Arrays.hashCode() 和Arrays.equals() 用于您的两个功能。
  • 出于某种原因,我看不到此解决方案有效。首先,根据作者的问题,有数百个数组需要处理。该解决方案将为每个数组创建一个对象,该对象可能在内存上很困难(如果涉及大量不同的数组)并最终使程序崩溃。其次,有效地访问该对象博客中的数组 hashCode 将存在问题。第三,该解决方案没有提供存储数组计算结果的方法。那么在做什么呢?
【解决方案2】:

正如其他人所建议的,您应该创建一个包装数组并以一致方式实现hashCode()和equals()的类。

其他答案建议将您的 int[] 数组转换为 String 或指示您应该对其进行迭代以计算哈希值或检查是否相等。

我建议您使用Java's Arrays 实用程序类来有效地计算基于数组的哈希值并检查数组是否相等:

public class Key {

    private final int[] values;

    public Key(int[] values) {
        this.values = values;
    }

    @Override
    public boolean equals(Object another) {
        if (another == this) {
            return true;
        }
        if (another == null) {
            return false;
        }
        if (another.getClass() != this.getClass()) {
            return false;
        }
        Key key = (Key) another;
        return Arrays.equals(this.values, key.values);
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(this.values);
    }
}

然后,在你的地图中使用它:

Map<Key, Integer> map = new LinkedHashMap<>(); // preserve insertion order?

int test[] = {1, 2, 3};
int test2[] = {1, 2, 3};

Key key = new Key(test);
Key key2 = new Key(test2);

map.put(key, 1);
map.put(key2, 1);

map.size(); // 1

注意:Key 的这个实现考虑了数组的元素顺序,这意味着如果由两个具有相同元素的数组构造而成,两个Keys 将是不同的订购:

int[] v1 = {1, 2, 3};
int[] v2 = {2, 1, 3};

Key k1 = new Key(v1);
Key k2 = new Key(v2);

k1.equals(k2); // false!

如果您希望两个Keys 相等,尽管它们的数组元素顺序相同,您应该在Key 类的构造函数中将int[] 数组转换为HashSet,然后实现Key 的@987654337 @ 和 hashCode() 方法通过在 HashSet 中委托给它们各自的实现。

【讨论】:

    【解决方案3】:

    我会创建特定于数组的键,然后将该键和计算结果存储在缓存中:

    public static void main() {
       Map<String, Integer> hashmap = new HashMap<>();
       int[] arr1 = {1, 2, 3};
       int[] arr2 = {1, 2, 3};
       hashmap.put(Arrays.hashCode(arr1), 1);
       hashmap.put(Arrays.hashCode(arr2), 1);
       System.out.println("Size: "+hashmap.size());
    }
    

    代码打印尺寸:1

    【讨论】:

    • Gregory Basior 的回答更像 Java。
    • 这是不正确的,因为两个不同数组的 hashCode 可能产生相同的值。这里就是使用key的equals操作来拆分差异的地方,但是这种方法不能提供自定义的equals操作。
    • @Solubris 为两个数组生成相同的哈希值是完全可以的,只要它们的内容相同。更多详情请见documentation
    • @MaxXoom 我说两个不同的数组可以有相同的哈希码,这就是数组中元素的值可以用来分隔键的地方,但是因为只使用了哈希码作为键,数组的元素不可用于任何哈希查找哈希映射。
    • @Solubris 你能给出一个支持你理论的代码示例吗?
    【解决方案4】:

    使用 Apache commons StringUtils.join() 方法创建唯一的数组键。它将一个数组作为参数,并在每个元素上调用 toString() 以获取每个元素的字符串表示形式。然后将每个元素字符串表示形式连接成一个字符串,如果指定了一个分隔符,则在其之间有一个分隔符:

    import org.apache.commons.lang3.StringUtils;
    
    int[] a = {1, 2, 3}
    String key= StringUtils.join(a, '-');
    System.out.println(key);
    

    生产:

    1-2-3

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-02
      • 2011-12-03
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      相关资源
      最近更新 更多