web-dev-qa-db-ja.com

Java method:既知の属性値が指定された配列リストでオブジェクトを検索する

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

クラス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があります。

Archiveでメソッドを記述しようとしています。このメソッドはIDとして整数を受け取り、ArrayListを調べて、そのIDを含むオブジェクトを返します。

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を持つオブジェクトを見つけたためにループが終了したかどうかを確認します。第二に、それは非常に時間のかかるプロセスのようです。これをスピードアップする方法はありますか?

21
Northener

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

ブロックがないので、whileは式dog=al.get(i);で終了します

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

その後のすべては一度だけ発生します。

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

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

編集:これはなぜですか?

OPからのコメント:

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

Java参照とそれが参照するオブジェクトは異なるものです。それらはC++参照とオブジェクトに非常によく似ていますが、Java参照は-C++ポインターのようにポイントされています。

要するに、_Dog dog;_または_Dog dog = null_は、オブジェクトを指していない参照を提供するということです。 new Dog()creates指すことができるオブジェクト。

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

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

結局のところ、犬を参照できる変数を作成する必要があるということです。 newでDogを作成する必要はありません。

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

16
tpdi

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

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

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

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

@Override
public boolean equals(Object obj) {     
   EqualsBuilder builder = new EqualsBuilder().append(this.getId(), obj.getId());               
   return builder.isEquals();
}
44
Jon

操作のパフォーマンスを向上させるために、常に一意の識別子でオブジェクトを検索する場合は、 _Map<Integer,Dog>_ の使用を検討できます。これにより、キーによる一定時間のルックアップが提供されます。マップ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回のルックアップだけを行う場合は、同じループオーバーヘッドが発生します。

16
Rob

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

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);
  }
}
13
Jorn

オリジナルのポスターが早期終了を回避するスタイルを使用しているのを見ることに興味がありました。単一のエントリ;単一出口(SESE)は、私が実際に検討したことのない興味深いスタイルです。遅れて、サイダーのボトルを手に入れたので、早期に終了せずにソリューションをテストしました。

イテレータを使用する必要がありました。残念ながら、_Java.util.Iterator_にはgetメソッドに副作用があります。 (例外の影響により、Iterator設計は好きではありません。)

_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;
}
_

i!=dogs.length()式の重複に注意してください(dogs.get(i).getID()!=idを選択した可能性があります)。

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());
}
});
0
Seth
List<YourClass> list = ArrayList<YourClass>();


List<String> userNames = list.stream().map(m -> m.getUserName()).collect(Collectors.toList());

出力:["John"、 "Alex"]

0
anson

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

int dogId = 2;

return dogList.stream().filter(dog-> dogId == dog.getId()).collect(Collectors.toList()).get(0);
0