web-dev-qa-db-ja.com

JavaのArrayListからオブジェクトを削除する

条件に一致する場合、ArrayListからいくつかのオブジェクトを削除する必要があり、どちらの方法がより効率的か疑問に思います。

状況は次のとおりです。他のオブジェクトを含むArrayListを含むクラスがあります。このArrayListを反復処理し、特定の条件を満たすすべての要素を削除する必要があります。私の知る限り、それらは削除する私のオプションです:

  1. 新しいArrayListを作成し、条件を満たさない要素を追加します。反復後、要素のない古い配列リストから新しい配列リストに交換します。

  2. 新しいArrayListを作成し、条件を満たす要素を追加します。繰り返し後、removeAll()メソッドを使用して、ArrayListに削除するオブジェクトを渡します。

ArrayListからオブジェクトを削除するより効率的な方法はありますか?

32
Carlos Pastor

別の方法:Iteratorには、ArrayListに実装されるオプションのremove()メソッドがあります。繰り返しながら使用できます。

ただし、どのバリアントが最もパフォーマンスが高いかはわかりません。測定する必要があります。

starblueは、複雑さは良くない、それは本当だとコメントしました(removeAll()の場合も同様です)。なぜなら、ArrayListはすべての要素をコピーする必要があるからです。その場合、LinkedListの方がうまく機能するはずです。しかし、実際のユースケースは誰も知らないので、最良のソリューションを選択するには、すべてのバリアントを測定するのが最善です。

16
Mnementh

ArrayListを通過するときに、逆方向に反復して削除できます。これには、後続の要素をシフトする必要がないという利点があり、前進するよりもプログラムが簡単です。

47
RichardOD

ほとんどのパフォーマンスは、 listIterator メソッドを使用し、逆の反復を行うことになると思います。

for (ListIterator<E> iter = list.listIterator(list.size()); iter.hasPrevious();){
    if (weWantToDelete(iter.previous()))  iter.remove();
}

編集:後で、追加することもできます Java 8要素を削除する方法 ラムダまたはメソッド参照を使用したリスト(または任意のコレクションから!)必要に応じて、コレクションのインプレース filter

list.removeIf(e -> e.isBad() && e.shouldGoAway());

これはおそらくコレクションをクリーンアップする最良の方法です。内部実装を使用するため、コレクションの実装はショートカットを使用して、可能な限り高速にすることができます(ArrayListsの場合、必要なコピーの量を最小限に抑えることができます)。

12
gustafc

明らかに、あなたが言及する2つの方法のうち、1番はリストを1回調べるだけでよいので、より効率的です。一方、2番の方法では、リストを2回走査する必要がありますそれらを削除します)。

実際、別のリストから要素のリストを削除することは、おそらくO(n)よりも悪いアルゴリズムなので、方法2はさらに悪いです。

イテレータメソッド:

List data = ...;

for (Iterator i = data.iterator(); i.hasNext(); ) {
    Object element = i.next();

    if (!(...)) {
        i.remove();
    }
}
5
Jesper

まず、これが実際にパフォーマンスのボトルネックであることを確認します。そうでない場合は、最もクリーンで表現力の高いソリューションを使用します。

それがISパフォーマンスのボトルネックである場合、さまざまな戦略を試してみて、何が最も速いかを見てください。

4
Buhb
int sizepuede= listaoptionVO.size();
for (int i = 0; i < sizepuede; i++) {
    if(listaoptionVO.get(i).getDescripcionRuc()==null){
        listaoptionVO.remove(listaoptionVO.get(i));
        i--;
        sizepuede--;
     }
}

編集:インデントを追加

1
Raulitoxd

ArrayListから要素を削除するには、隠れたコストがかかります。要素を削除するたびに、要素を移動して「穴」を埋める必要があります。平均して、これはN個の要素を持つリストに対して_N / 2_割り当てを取ります。

したがって、N要素のArrayListからM要素を削除すると、平均でO(M * N)になります。 O(N)ソリューションには、新しいリストの作成が含まれます。

_List data = ...;
List newData = new ArrayList(data.size()); 

for (Iterator i = data.iterator(); i.hasNext(); ) {
    Object element = i.next();

    if ((...)) {
        newData.add(element);
    }
}
_

Nが大きい場合、このアプローチは、Mの値が3または4の場合にremoveアプローチよりも高速になると思います。

ただし、newList内のすべての要素を保持するのに十分な大きさのlistを作成して、展開時に補助配列をコピーしないようにすることが重要です。

1
Stephen C

あなたが直面している問題が実際にボトルネックであると肯定的でない限り、私は読みやすいものを選びます

public ArrayList filterThings() {

    ArrayList pileOfThings;
    ArrayList filteredPileOfThings = new ArrayList();

    for (Thing thingy : pileOfThings) {
        if (thingy.property != 1) {
            filteredPileOfThings.add(thingy);
        }            
    }
    return filteredPileOfThings;
}
1
thomax

私は代替のより速い解決策を見つけました:

  int j = 0;
  for (Iterator i = list.listIterator(); i.hasNext(); ) {
    j++;

    if (campo.getNome().equals(key)) {
       i.remove();
       i = list.listIterator(j);
    }
  }
0
Matteo Fattore

多分 イテレータ ’s remove() メソッド? JDKのデフォルトのコレクションクラスは、このメソッドをサポートするすべてのクリエーターイテレーターでなければなりません。

0
Bombe

これは直感に反しますが、これはこの操作を大幅に高速化する方法です。

まさに私がやっていたこと:

ArrayList < HashMap < String , String >> results; // This has been filled with a whole bunch of results

ArrayList <HashMap <String、String>> discard = findResultsToDiscard(results);

results.removeall(discard);

ただし、remove allメソッドは、2000(ish)の配列から約800の結果を削除するために6秒以上かかりました(破棄結果を取得するメソッドを含まない)。

この投稿でgustafcなどが提案したイテレータメソッドを試しました。

これにより、操作がわずかに(約4秒に)短縮されましたが、それでも十分ではありませんでした。だから私は危険な何かを試してみました...

 ArrayList < HashMap < String, String>> results;

  List < Integer > noIndex = getTheDiscardedIndexs(results);

for (int j = noIndex.size()-1; j >= 0; j-- ){
    results.remove(noIndex.get(j).intValue());
}

getTheDiscardedIndexsはHashMapsの配列ではなく、インデックスの配列を保存します。これにより、オブジェクトの削除がより高速になり(現在では約0.1秒)、削除する結果の大きな配列を作成する必要がないため、メモリの効率が向上します。

これが誰かを助けることを願っています。

0
Aiden Fry

イテレータを使用すると、指定されたインデックスではなく、常に順序付けられる要素を処理できます。したがって、上記の問題に悩まされるべきではありません。

Iterator itr = list.iterator();
String strElement = "";
while(itr.hasNext()){

  strElement = (String)itr.next();
  if(strElement.equals("2"))
  {
    itr.remove();
  }
0
Rakshi