20

奇妙な問題が発生しました。これには数分かかると思いましたが、今は数時間苦労しています...これが私が得たものです:

for (int i = 0; i < size; i++){
    if (data.get(i).getCaption().contains("_Hardi")){
        data.remove(i);
    }
}

これdataArrayList. 、ArrayListにいくつかの文字列(合計14個程度)があり、そのうちの9個に_Hardiという名前が付いています。

そして、上記のコードでそれらを削除したいと思います。_HardiがArrayListに9回含まれているので、それをreplace data.remove(i);使用すると、System.out.println何かが9回出力されます。これは良いことです。

しかし、私が使用するdata.remove(i);と、9つすべてが削除されるわけではなく、ごく一部が削除されます。私はいくつかのテストを行いました、そして私はこれも見ました:

文字列の名前を次のように変更すると、Hardi1 Hardi2 Hardi3 Hardi4 Hardi5 Hardi6

次に、偶数(1、3、5など)のみを削除します。彼はいつも1をスキップしていますが、理由がわかりません。

これを修正する方法は?それとも、それらを削除する別の方法ですか?

4

14 に答える 14

53

ここでの問題は、0からサイズまで繰り返し、ループ内でアイテムを削除していることです。アイテムを削除すると、リストのサイズが小さくなり、有効サイズ(削除されたアイテムの後のサイズ)よりも大きいインデックスにアクセスしようとすると失敗します。

これを行うには2つのアプローチがあります。

インデックスを処理したくない場合は、イテレータを使用して削除してください。

for (Iterator<Object> it = data.iterator(); it.hasNext();) {
if (it.next().getCaption().contains("_Hardi")) {
    it.remove();
}
}

それ以外の場合は、最後から削除します。

for (int i = size-1; i >= 0; i--){
    if (data.get(i).getCaption().contains("_Hardi")){
            data.remove(i);
    }
 }
于 2012-05-24T13:48:30.563 に答える
20

リストを繰り返し処理している間は、リストからアイテムを削除しないでください。代わりに、次のIterator.remove()ように使用します。

for (Iterator<Object> it = list.iterator(); it.hasNext();) {
    if ( condition is true ) {
        it.remove();
    }
}
于 2012-05-24T13:41:22.743 に答える
12

アイテムを削除するたびに、その前のアイテムのインデックスが変更されます(したがって、list [1]を削除すると、list[2]はlist[1]になるため、スキップされます。

これを回避するための本当に簡単な方法は次のとおりです:(カウントアップではなくカウントダウン)


for(int i = list.size() - 1; i>=0; i--)
{
  if(condition...)
   list.remove(i);
}

于 2012-05-24T13:50:06.767 に答える
5

これは、リストから要素を削除すると、リストの要素が上に移動するためです。したがって、最初の要素、つまりインデックス0を削除すると、インデックス1の要素はインデックス0にシフトされますが、ループカウンターは反復ごとに増加し続けます。したがって、更新された0番目のインデックス要素を取得する代わりに、1番目のインデックス要素を取得します。したがって、リストから要素を削除するたびに、カウンターを1つ減らしてください。

以下のコードを使用して、正常に動作させることができます。

for (int i = 0; i < data.size(); i++){
    if (data.get(i).getCaption().contains("_Hardi")){
        data.remove(i);
        i--;
    }
}
于 2013-06-11T11:56:42.623 に答える
4

あなたがそれを熟考するならば、それは完全に理にかなっています。リストがあるとしましょう[A, B, C]。ループの最初のパス、i == 0。要素が表示Aされてから削除されるため、リストはになり[B, C]、要素0はになりBます。ここiで、ループの最後でインクリメントするので、list[1]どちらがであるかを確認しますC

1つの解決策は、アイテムを削除するたびにデクリメントiして、後続のインクリメントを「キャンセル」することです。matt bが上で指摘しているように、より良い解決策Iterator<T>は、組み込みremove()関数を持つanを使用することです。

一般的に言えば、このような問題に直面したときは、一枚の紙を取り出して、自分がコンピューターのふりをすることをお勧めします。ループの各ステップを実行し、すべての変数を書き留めます。それは「スキップ」を明確にしたでしょう。

于 2012-05-24T13:48:06.863 に答える
4

このソリューションがほとんどの人にとって最適である理由がわかりません。

for (Iterator<Object> it = data.iterator(); it.hasNext();) {
    if (it.next().getCaption().contains("_Hardi")) {
        it.remove();
    }
}

次の行に移動されたため、3番目の引数は空です。さらにit.next()、ループの変数をインクリメントするだけでなく、データを取得するためにも使用しています。私にとって、forループの使用は誤解を招きます。なぜ使用しないのwhileですか?

Iterator<Object> it = data.iterator();
while (it.hasNext()) {
    Object obj = it.next();
    if (obj.getCaption().contains("_Hardi")) {
            it.remove();
    }
}
于 2016-12-22T13:56:30.257 に答える
3

値を削除すると、インデックスが適切でなくなるため

sizeまた、1つの要素を削除するとサイズが変更されるため、に移動できなくなります。

あなたはそれiteratorを達成するためにを使うかもしれません。

于 2012-05-24T13:41:10.033 に答える
3
for (Iterator<Object> it = data.iterator(); it.hasNext();) {
    if ( it.getCaption().contains("_Hardi")) {
        it.remove(); // performance is low O(n)
    }
}

削除操作がリストに多く必要な場合。LinkedListを使用すると、パフォーマンスが O(1)大幅に向上します(大まかに)。

ArrayListのパフォーマンスはO(n)(おおよそ)どこにありますか。そのため、削除操作への影響は非常に大きくなります。

于 2012-05-24T13:48:40.307 に答える
3

既存の回答に加えて、条件付きの増分で通常のwhileループを使用できます。

int i = 0;
while (i < data.size()) {
    if (data.get(i).getCaption().contains("_Hardi"))
        data.remove(i);
    else i++;
}

data.size()ループ状態では毎回呼び出す必要があることに注意してください。そうしないと、IndexOutOfBoundsException削除されたすべてのアイテムがリストの元のサイズを変更するため、最終的にはになります。

于 2014-08-31T21:50:17.500 に答える
3

遅いですが、誰かのために働くかもしれません。

Iterator<YourObject> itr = yourList.iterator();

// remove the objects from list
while (itr.hasNext())
{
    YourObject object = itr.next();
    if (Your Statement) // id == 0
    {
        itr.remove();
    }
}
于 2015-12-14T16:32:48.723 に答える
2

これは、要素を削除することにより、のインデックスを変更するために発生しますArrayList

于 2012-05-24T13:40:42.590 に答える
2
import java.util.ArrayList;

public class IteratorSample {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        ArrayList<Integer> al = new ArrayList<Integer>();
        al.add(1);
        al.add(2);      
        al.add(3);
        al.add(4);

        System.out.println("before removal!!");
        displayList(al);

        for(int i = al.size()-1; i >= 0; i--){
            if(al.get(i)==4){
                al.remove(i);
            }
        }

        System.out.println("after removal!!");
        displayList(al);


    }

    private static void displayList(ArrayList<Integer> al) {
        for(int a:al){
            System.out.println(a);
        }
    }

}

出力:

撤去前!! 1 2 3 4

取り外した後!! 1 2 3

于 2016-09-09T08:01:51.573 に答える
2

新しいイテレータオブジェクトを作成せずに、この問題を解決する簡単な方法があります。これがコンセプトです。arrayListに名前のリストが含まれているとします。

names = [James, Marshall, Susie, Audrey, Matt, Carl];

Susieからすべてを削除するには、Susieのインデックスを取得し、それを新しい変数に割り当てます。

int location = names.indexOf(Susie);//index equals 2

インデックスができたので、arrayListから値を削除する回数をカウントするようにjavaに指示します。

for (int i = 0; i < 3; i++) { //remove Susie through Carl
    names.remove(names.get(location));//remove the value at index 2
}

ループ値が実行されるたびに、arrayListの長さが短くなります。インデックス値を設定し、値を削除する回数をカウントしているので、すべて設定されています。各パススルー後の出力の例を次に示します。

                           [2]
names = [James, Marshall, Susie, Audrey, Matt, Carl];//first pass to get index and i = 0
                           [2]
names = [James, Marshall, Audrey, Matt, Carl];//after first pass arrayList decreased and Audrey is now at index 2 and i = 1
                           [2]
names = [James, Marshall, Matt, Carl];//Matt is now at index 2 and i = 2
                           [2]
names = [James, Marshall, Carl];//Carl is now at index 3 and i = 3

names = [James, Marshall,]; //for loop ends

最終的なメソッドがどのように見えるかのスニペットを次に示します。

public void remove_user(String name) {
   int location = names.indexOf(name); //assign the int value of name to location
   if (names.remove(name)==true) {
      for (int i = 0; i < 7; i++) {
         names.remove(names.get(location));
      }//end if
      print(name + " is no longer in the Group.");
}//end method
于 2017-02-28T03:11:47.983 に答える
2

これは、配列リストを使用する際の一般的な問題であり、配列リストの長さ(サイズ)が変更される可能性があるために発生します。削除すると、サイズも変わります。したがって、最初の反復の後、コードは混乱します。最善のアドバイスは、イテレータを使用するか、後ろからループすることです。ただし、それほど複雑ではなく、多くの要素で正常に機能すると思うので、バックワードループをお勧めします。

//Let's decrement!
for(int i = size-1; i >= 0; i--){
    if (data.get(i).getCaption().contains("_Hardi")){
        data.remove(i);
    }
 }

それでも古いコードは、ループが異なるだけです!

これがお役に立てば幸いです...

メリーコーディング!!!

于 2017-12-13T21:53:50.710 に答える