Java:如何确保基于List上的值存储唯一数组

时间:2009-10-20 15:45:57

标签: java arrays hashcode

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

我想将这些数组存储在List中,但只存储其内容与其余数据不同的数组。

我的第一个aproximation是通过存储在Arrays.hashCode(array)的值中的数组进行迭代,并且只有在该值没有被包含在集合中时才将数组存储在所需的列表中。

但后来我意识到两个内容不同的数组可以生成相同的哈希码(我不希望这样做)

任何人都可以帮忙吗?

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

6 个答案:

答案 0 :(得分:2)

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

我想说定义一个比较器,它为数组定义“相等”,确切地说你需要它如何定义,然后将每个数组插入一个使用你创建的自定义比较器的Set中。

答案 1 :(得分:2)

听起来你需要一个LinkedHashSet(在保持唯一性的同时保留插入顺序),然​​后将你的数组包装在一个实现hashcode的对象中,并且对你的数组有意义。第一个近似可能只是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; 
       } 
 }

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

将数组转换为List。列表具有一致的equalshashCode方法。 如果两个列表包含相同顺序的相同元素,则它们被定义为相等,而List的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;
}

答案 4 :(得分: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,您可以告诉该集合等于什么。

Arrays.equals()方法描述:

  

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

答案 5 :(得分:0)

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

  1. hashCode放弃了许多潜在的匹配
  2. 如果两个hashCode相等,则对象本身进行相等性测试(取决于他们的方法equals

  3. 关于Object[]原始类型,请记住以下内容:
    要在Object[]中添加基本类型,它将始终为装箱/取消装箱
    所以你并没有真正的基本类型作为数组的内容。

    要保留基元类型,数组本身必须是基本类型,例如int[]