21

実はいくつか質問があります。

次のインスタンス フィールドを持つクラスDogがあります。

private int id;
private int id_mother;
private int id_father;
private String name="";
private String owner="";
private String bDate="";

また、 Dogをインスタンス化し、Dog オブジェクトを ArrayList に入れることができるArchiveクラスもあります。

ID として整数を取り、ArrayList を調べて、その ID を含むオブジェクトを返すメソッドをArchiveに書き込もうとしています。

private Dog getDog(int id){
    Dog dog = new Dog();
    int length=getSize();
    int i=0;

    dog=al.get(i);
    i++;

    while(dog.getId()!=id && i<length)
        dog=al.get(i);
        i++;

    if(dog.getId()!=id)
        dog=null;
    return dog;
}//end getDog

この方法には 2 つの問題があります (私が使用する他の方法は機能します)。まず第一に、それは機能していません。その理由はわかりません。ループが終了した後、検索するオブジェクトがなくなったためにループが終了したかどうか、または指定された ID を持つオブジェクトが見つかったためにループが終了したかどうかを確認します。 . 第二に、それは非常に時間のかかるプロセスのようです。これをスピードアップする方法はありますか?

4

8 に答える 8

44

Dog の ID に基づいて比較する Dog の equals メソッドを正しく記述したと仮定すると、リスト内の項目を返す最も簡単で簡単な方法は次のとおりです。

if (dogList.contains(dog)) {
   return dogList.get(dogList.indexOf(dog));
}

これは、ここでの他のアプローチよりもパフォーマンス集約的ではありません。この場合、ループはまったく必要ありません。お役に立てれば。

PS Apache Commons Lang を使用して、Dog の単純な equals メソッドを次のように記述できます。

@Override
public boolean equals(Object obj) {     
   EqualsBuilder builder = new EqualsBuilder().append(this.getId(), obj.getId());               
   return builder.isEquals();
}
于 2009-04-11T01:34:43.063 に答える
16

は、のwhile後の式またはブロックに適用されますwhile

あなたはブロックを持っていないので、あなたの while は式で終わりますdog=al.get(i);

while(dog.getId()!=id && i<length)
                dog=al.get(i);

それ以降はすべて一度だけ発生します。

新しい犬を使用することは決してないので、犬を新しくする理由はありません。すぐに配列から Dog 参照​​に Dog を割り当てます。

また、キーの値を取得する必要がある場合は、配列ではなくマップを使用する必要があります。

編集: これはなぜ dowmodded でしたか??

OPからのコメント:

Dog の新しいインスタンスを作成する必要がないことに関して、もう 1 つの質問があります。配列リストからオブジェクトのコピーを取り出しているだけの場合、オブジェクトを配置せずに配列リストからそれを取り出すにはどうすればよいでしょうか? while ループを囲んでいないことにも気付きました。

Java 参照とそれが参照するオブジェクトは別のものです。Java 参照は C++ ポインターのように再指定できますが、これらは C++ 参照およびオブジェクトに非常によく似ています。

結論は、オブジェクトを指していない参照を提供することですDog dog;。指し示すことができるオブジェクトを作成します。Dog dog = nullnew Dog()

それに続いて、dog = al.get(i)参照が によって返された犬の参照を指していることを意味しal.get(i)ます。Java では、オブジェクトが返されることはなく、オブジェクトへの参照 (メモリ内のオブジェクトのアドレス) のみが返されることを理解してください。

参照対象が から取得した参照対象に置き換えられたため、コードがそれを参照していないため、新しく作成した Dog のポインタ/参照/アドレスは失われていますal.get()。最終的に Java ガベージ コレクタはそのオブジェクトを破棄します。C++ では、メモリを「リーク」していたでしょう。

つまり、Dog を参照できる変数を作成する必要があります。で Dog を作成する必要はありませんnew

(実際には、参照を作成する必要はありません。実際に行うべきことは、Map がその get() 関数から返すものを返すことです。Map が Dog でパラメータ化されていない場合は、次のようMap<Dog>になります: ' get からの戻り値をキャストする必要がありますが、参照は必要ありません:return (Dog) map.get(id);または Map がパラメーター化されている場合return map.get(id). そして、その 1 行が関数全体であり、ほとんどの場合、配列を反復するよりも高速です。 )

于 2009-04-10T23:57:44.793 に答える
16

操作のパフォーマンスを向上させるために、一意の識別子で常にオブジェクトを検索する場合は、Map<Integer,Dog>. これにより、キーによる一定時間のルックアップが提供されます。map を使用してオブジェクト自体を反復処理することもできますvalues()

開始するための簡単なコード フラグメント:

// Populate the map
Map<Integer,Dog> dogs = new HashMap<Integer,Dog>();
for( Dog dog : /* dog source */ ) {
    dogs.put( dog.getId(), dog );
}

// Perform a lookup
Dog dog = dogs.get( id );

これは、リストで同じ性質の複数の検索を実行している場合に、処理を少し高速化するのに役立ちます。ルックアップを 1 回だけ実行している場合は、関係なく同じループ オーバーヘッドが発生します。

于 2009-04-11T00:21:37.357 に答える
13

配列全体をループする必要があります。それを変更することはできません。ただし、少し簡単に行うことができます

for (Dog dog : list) {
  if (dog.getId() == id) {
    return dog; //gotcha!
  }
}
return null; // dog not found.

または新しいforループなし

for (int i = 0; i < list.size(); i++) {
  if (list.get(i).getId() == id) {
    return list.get(i);
  }
}
于 2009-04-11T00:00:10.747 に答える
1

I was interested to see that the original poster used a style that avoided early exits. Single Entry; Single Exit (SESE) is an interesting style that I've not really explored. It's late and I've got a bottle of cider, so I've written a solution (not tested) without an early exit.

I should have used an iterator. Unfortunately java.util.Iterator has a side-effect in the get method. (I don't like the Iterator design due to its exception ramifications.)

private Dog findDog(int id) {
    int i = 0;
    for (; i!=dogs.length() && dogs.get(i).getID()!=id; ++i) {
        ;
    }

    return i!=dogs.length() ? dogs.get(i) : null;
}

Note the duplication of the i!=dogs.length() expression (could have chosen dogs.get(i).getID()!=id).

于 2009-04-11T00:51:54.383 に答える
0

ID ではない属性を取得する必要がある場合。CollectionUtilsを使用します。

Dog someDog = new Dog();
Dog dog = CollectionUtils(dogList, new Predicate() {

@Override
public boolean evaluate(Object o)
{
    Dog d = (Dog)o;
    return someDog.getName().equals(d.getName());
}
});
于 2013-05-05T22:27:40.333 に答える
0

Java 8ラムダを使用してこれを解決しました

int dogId = 2;

return dogList.stream().filter(dog-> dogId == dog.getId()).collect(Collectors.toList()).get(0);
于 2017-08-23T14:10:28.207 に答える