1

少しおかしく聞こえるかもしれませんが、私の言いたいことを説明すると:

非常に遅い初期化オブジェクトをいくつか含む(HashSet など) があり、特定のオブジェクトが既に含まれているCollectionかどうかを確認したいと考えています。例としてCollection使用しましょう(初期化に費用がかからないことはわかっています)。Vector3d

したがって、Collection含まれています:

Vector3d(1,1,1)
Vector3d(2,1,1)
Vector3d(3,1,1)

そして、「 には with が含まれていますか (つまり、メソッドがハッシュするデータを既に知っています)」という質問をしたいので、新しいものを作成してから使用することができますがCollection、オブジェクトの初期化が遅いと言ったように、または手動でチェック全体を実行することもできますが(これは私が今行っていることです)、それは(私が理解しているように)ハッシュを使用しないためより遅くなります.これを行うより良い方法はありますか?CollectionVector3dx=2y=1z=1.contains()Vector3d(2,1,1).contains()Collection.contains()

問題のオブジェクトは変更可能ですが、equalsメソッドが基づいているデータはそうではありません。(私の場合、それらは x、y、z 座標のブロックです。ブロックの内容は変更される可能性がありますが、x、y、z 座標は変更されません)

4

6 に答える 6

2

.contains()でメソッドを使用するArrayListと、equals内のすべてのインスタンスに対してメソッドが呼び出されますArrayList

それはあなたにとってはうまくいきますが、非常に大きなArrayLists には有益ではないかもしれません. パフォーマンスが問題になる場合は、オブジェクトHashSetへの包含参照を保持することをお勧めしVector3dます。containsa HashSet(または any ) の呼び出しSetは大幅に高速です。

于 2013-04-20T22:10:49.623 に答える
2

ArrayList は、すべての要素を繰り返し処理するか、位置によって要素にアクセスするだけでよい場合に適したデータ構造です。それは他のものにとって間違ったデータ構造です。

あなたがやろうとしているのは、封じ込めの質問に素早く答えることです。それがセットとマップの目的です。必要な単純なハッシュ関数を使用して別の安価なクラスを作成し、高価なオブジェクトをと同時に、または代わりに にVector3dKey挿入する方がはるかに理にかなっています。Java は明らかに、高価なベクトルのコピーを 2 つ保持するのではなく、参照のコピーのみを保持します。もちろん、 Vector がmutableの場合、このスキーム全体が機能しなくなります。Map< Vector3dKey, Vector3d >ArrayList< Vector3d >

于 2013-04-21T04:03:42.890 に答える
1

メンタル裁判官の回答に基づくコード

package mygame;

import java.util.HashMap;
import java.util.Map;


public class Main{


    public Main(){
        Map<CheapKey,ExpensiveClass> map=new HashMap< CheapKey, ExpensiveClass>();

        for(int i=0;i<100;i++){
            ExpensiveClass newExpensiveClass;
            newExpensiveClass=new ExpensiveClass(i,0,0);
            map.put(newExpensiveClass.getKey(), newExpensiveClass);
        }

        CheapKey testKey1=new CheapKey(1,0,0);
        CheapKey testKey2=new CheapKey(1,0,1);

        System.out.println(map.containsKey(testKey1)); //there is an object under key1
        System.out.println(map.containsKey(testKey2)); //there isn't an object under key2
        ExpensiveClass  retrievedExpensiveClass=map.get(testKey1);
    }

    public static void main(String[] args) {
        Main main=new Main();
    }

    protected class ExpensiveClass{
        int x;
        int y;
        int z;
        public ExpensiveClass(int x, int y, int z){
            this.x=x;
            this.y=y;
            this.z=z;
            for(int i=0;i<10000;i++){
                //slow initilisation
            }

        }
        public CheapKey getKey(){
            return new CheapKey(x,y,z);
        }

    }

    protected class CheapKey{
        int x;
        int y;
        int z;
        public CheapKey(int x, int y, int z){
            this.x=x;
            this.y=y;
            this.z=z;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final CheapKey other = (CheapKey) obj;
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 79 * hash + this.x;
            hash = 79 * hash + this.y;
            hash = 79 * hash + this.z;
            return hash;
        }


    }



}
于 2013-04-21T14:24:41.827 に答える
0

ArrayList.containsハッシュを使用しません。手動チェックとまったく同じ速度です。どちらの方法でも違いはありません。

偽のオブジェクト クラスを使用することは可能ですが、ほぼ確実にコードの匂いがします。

于 2013-04-20T22:10:29.177 に答える
0

contains メソッドはオブジェクトの .equals メソッドを呼び出すため、そのクラスの .equals の実装が値を比較する限り、それらのポインターではなくオブジェクトに含まれる値を比較し、contains の使用は機能します。

http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html#contains(java.lang.Object)

あなたの質問を少し誤解して編集してください。それは、リストの大きさと初期化にかかる時間に帰着すると思います。リストが短い場合は、反復して手動で確認します。ただし、リストが長くなる可能性がある場合は、オブジェクトを作成して .contains を使用する方が効率的です。

于 2013-04-20T22:06:24.413 に答える