代码之家  ›  专栏  ›  技术社区  ›  Telcontar

Java:如何确保基于列表中的值存储唯一的数组

  •  2
  • Telcontar  · 技术社区  · 15 年前

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

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

    我的第一个建议是通过将数组的值存储在一个集合中的数组进行迭代。哈希代码(array),并且仅当数组的值未包含在集合中时将数组存储在所需的列表中。

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

    有人能帮忙吗?

    我能预料到非常奇怪的哈希代码冲突吗(相同的哈希代码来自不同的内容)?

    6 回复  |  直到 14 年前
        1
  •  2
  •   Yishai    15 年前

    听起来您需要一个Linkedhashset(在保持唯一性的同时保留插入顺序),然后将数组包装在一个实现哈希代码和相等的对象中,这样对数组来说是有意义的。第一个近似值可能只是arrays.aslist()方法,但您在问题中声明正在对象[]数组中使用基元。或者您依赖于自动氧化,或者您实际上没有使用对象[]数组,而是根据需要使用int[]、long[]、float[]。array.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
  •  2
  •   Brienne Schroth    15 年前

    问题是你会有arrayx和arrayy,两者都有内容[a,b,c],但是集合不把它们视为相等的吗?[a,b,c]和[c,a,b]是否被视为相等?

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

        3
  •  1
  •   NawaMan    15 年前

    如果散列代码相同,则只需进一步检查其详细信息。

        4
  •  1
  •   OscarRyz    15 年前

    尝试如下操作:

    编辑

    运行和工作代码如下:

    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$ 
    

    为了使它工作,您需要做一些工作,这只是一个示例,而不是实际运行的代码。

    如您所知,集合只接受一个元素,并创建 TreeSet 使用一个定制的比较器,您可以告诉集合什么对您来说是相等的。

    Arrays.equals() 方法描述:

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

        5
  •  1
  •   Juha Syrjälä    15 年前

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

    不要将数组的哈希代码存储到集合中,而是将整个列表存储到集合中。

    将数组转换为 List S.清单一致 equals 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;
    }
    
        6
  •  0
  •   KLE rslite    15 年前

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

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

    关于你 Object[] 属于原始类型,请记住以下内容:
    将基元类型添加到 对象[ ] ,它将永远是 盒装/未装箱 .
    因此,您没有真正的基元类型作为数组的内容。

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