2

Object[] の 1 次元配列が多数あります (これらのオブジェクトは、役立つ場合はプリミティブ型です)

これらの配列をリストに格納したいのですが、残りの配列とは一意の内容を持つ配列のみです。

私の最初の近似は、Arrays.hashCode(array) の値をセットに格納する配列を反復処理し、値がセットに含まれていない場合にのみ、目的のリストに配列を格納することでした。

しかし後で、内容が異なる2つの配列が同じハッシュコードを生成できることに気付きました(頻繁ではないことを願っています)

誰でも助けることができますか?

非常に頻繁にハッシュコードの衝突 (異なるコンテンツからの同じハッシュコード) を期待できますか?

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に変換します。リストには一貫したequalsメソッドとhashCodeメソッドがあります。2 つのリストは、同じ要素が同じ順序で含まれている場合に等しいと定義され、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;
}
于 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$ 

これは単なるサンプルであり、実際に実行するコードではありません。

ご存じのように、セットは 1 つの要素のみを受け入れTreeSet、カスタム コンパレータを使用して を作成すると、何が等しいかをセットに伝えることができます。

Arrays.equals()メソッドについて説明します。

..同じ要素が同じ順序で含まれている場合、2 つの配列は等しいです...

于 2009-10-20T16:01:45.843 に答える
0

効率的に比較するために、2 段階のアプローチを使用することがあります。

  1. hashCode多くの潜在的な一致を破棄します
  2. 2 つの hashCode が等しい場合、オブジェクト自体が等しいかどうかがテストされます (メソッドによって異なりますequals) 。

プリミティブ型であることについてObject[]は、次のことを覚えておいてください:
プリミティブ型を に追加するにはObject[]、常にboxed/unboxedになります。
したがって、配列の内容としてプリミティブ型は実際にはありません。

プリミティブ型を保持するには、配列自体が などのプリミティブ型である必要がありますint[]

于 2009-10-20T15:58:53.930 に答える