2

我有许多 Object[] 的一维数组(如果有帮助,这些对象是原始类型)

我想将这些数组存储在一个列表中,但只有其内容与其他数组不同的数组。

我的第一个近似值是遍历存储在 Set 中的数组 Arrays.hashCode(array) 的值,并且如果该值未包含在集合中,则仅将数组存储在所需的列表中。

但后来我意识到两个具有不同内容的数组可以产生相同的哈希码(我希望不经常)

谁能帮忙?

我可以期待非常频繁的哈希码冲突(来自不同内容的相同哈希码)吗?

4

6 回答 6

2

问题是您将拥有 arrayX 和 arrayY,两者都具有内容 [a,b,c] 但 Set 不将它们视为平等?[a,b,c] 和 [c,a,b] 是否会被视为相等?

我会说定义一个比较器,它为数组定义“相等”,正是你需要它定义的方式,然后将每个数组插入到使用你创建的自定义比较器的 Set 中。

于 2009-10-20T15:57:11.773 回答
2

听起来您需要一个 LinkedHashSet (在保持唯一性的同时保留插入顺序),然​​后将数组包装在一个对象中,该对象以对数组有意义的方式实现哈希码和相等。第一个近似值可能只是 Arrays.asList() 方法,但您在问题中声明您在 Object[] 数组中使用原语。要么您依赖自动装箱,要么您实际上没有使用 Object[] 数组,而是根据需要使用 int[]、long[]、float[]。Arrays.asList() 无法与这些类型一起正常工作。

编辑:根据评论的要求,这里是包装类的代码:

  public class ArrayWrapper { 
       private Object[]array; 
       public ArrayWrapper(Object[] array) { this.array = array; } 
       public Object[] getArray() { 
                 Object[] newArray=new Object[array.length]; 
                 System.arraycopy(array,0,newArray,0,array.length); 
                  return newArray; 
       } 
       public int hashCode() { return Arrays.hashCode(array); } 
       public boolean equals(Object obj) { 
              boolean b=false;
              if(obj instanceof ArrayWrapper){ 
                     b=Arrays.equals(this.array,((ArrayWrapper)obj).getArray()); 
              } 
              return b; 
       } 
 }
于 2009-10-20T15:58:52.473 回答
1

如果哈希码相同,那么您只需进一步检查其详细信息。

于 2009-10-20T15:49:47.723 回答
1

以下假设您认为数组 {1,2,3} 和 {3,2,1} 不重复。

不要将数组的哈希码存储到 Set,将整个列表存储到 Set。

将您的数组转换为List。列表具有一致的equalshashCode方法。如果两个列表包含相同顺序的相同元素,则定义为相等,并且列表的 hashCode 将与 equals 方法一致。

  List<Object> list = Arrays.asList(array);

这是整个算法。(未经测试的代码,但应该可以工作)。

Set<List<Object>> findUniqueLists(List<List<Object>> allLists) {
   Set<List<Object>> uniqueSet = new LinkedHashSet<List<Object>>();
   uniqueSet.addAll(allLists);

   Set<List<Object>> processedSet = new LinkedHashSet<List<Object>>();

   for(List<Object> list : allLists) {
       if(processedSet.contains(list)) {
           // duplicate found!
           uniqueSet.remove(list);
       } else {
           // no duplicate
           processedSet.add(list)
       }
    }
    return uniqueSet;
}
于 2009-10-20T15:57:37.170 回答
1

尝试这样的事情:

编辑

运行和工作代码如下:

bash-3.2$ cat ArraysTest.java 
import java.util.*;
public class ArraysTest {
    public static void main( String [] args ) {
        Set<Integer[]> set = new TreeSet<Integer[]>( new Comparator<Integer[]>() {
            public int compare( Integer[] one, Integer[] two ) {
                if( Arrays.equals( one, two ) )  {
                    return 0;
                }
                return Arrays.hashCode( one ) - Arrays.hashCode( two );
            }
            public boolean equals( Object o ){ return false; }
        });

        set.add( new Integer[]{1,2,3});
        set.add( new Integer[]{1,2,3});
        set.add( new Integer[]{3,2,1});

        for( Integer[] i : set ) {
            System.out.println( Arrays.asList( i ) );
        }

    }
}

bash-3.2$ javac ArraysTest.java  
bash-3.2$ java ArraysTest
[1, 2, 3]
[3, 2, 1]
bash-3.2$ 

您必须做一些工作才能使其正常工作,这只是一个示例,而不是实际运行的代码。

如您所知, Set 只接受一个元素,并且TreeSet使用自定义比较器创建它可以让您告诉 set 什么对您来说是相等的。

Arrays.equals()方法描述:

..如果两个数组以相同的顺序包含相同的元素,则它们相等...

于 2009-10-20T16:01:45.843 回答
0

为了有效地比较,有时使用两步方法:

  1. hashCode丢弃许多潜在的匹配项
  2. 如果两个 hashCode 相等,则测试对象本身是否相等(取决于它们的方法equals

关于您Object[]是原始类型,请记住以下几点:
要将原始类型添​​加到 中Object[],它将始终被装箱/取消装箱
因此,您实际上并没有原始类型作为数组的内容。

为了保留原始类型,数组本身必须是原始类型,例如int[].

于 2009-10-20T15:58:53.930 回答