JavaRush /Java Blog /Random-JA /Java での ArrayList からの要素の削除

Java での ArrayList からの要素の削除

Random-JA グループに公開済み
こんにちは!前回の講義では、 ArrayListクラスについて理解し、それを使用して最も一般的な操作を実行する方法も学びました。さらに、ArrayList と通常の配列の間にはかなりの違いがあることも確認しました。次に、ArrayList から要素を削除する方法を見てみましょう。通常の配列の要素を削除するのはあまり便利ではないことはすでに述べました。ArrayList からの要素の削除 - 1セル自体を削除することはできないため、その値を「ゼロ」にすることしかできません。
public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat[] cats = new Cat[3];
       cats[0] = new Cat("Thomas");
       cats[1] = new Cat("Hippopotamus");
       cats[2] = new Cat("Philip Markovich");

       cats[1] = null;

       System.out.println(Arrays.toString(cats));
   }


@Override
   public String toString() {
       return "Cat{" +
               "name='" + name + '\'' +
               '}';
   }
}
結論:

[Cat{name='Томас'}, null, Cat{name='Фorпп Маркович'}]
しかし、リセットすると、アレイに「穴」が残ります。セルを削除するのではなく、その内容のみを削除します。50 匹の猫の配列があり、そのうち 17 匹をこの方法で削除した場合に何が起こるかを想像してください。17個の穴を備えたアレイを用意して、面倒を見てみましょう。新しい値を書き込むことができる空のセルの数を暗記することは非現実的です。一度間違えると、オブジェクトへの目的の参照でセルが上書きされてしまいます。もちろん、もう少し慎重に行う方法もあります。削除した後、「穴」が最後になるように配列の要素を先頭に移動します。
public static void main(String[] args) {

   Cat[] cats = new Cat[4];
   cats[0] = new Cat("Thomas");
   cats[1] = new Cat("Hippopotamus");
   cats[2] = new Cat("Philip Markovich");
   cats[3] = new Cat("Fluff");

   cats[1] = null;

   for (int i = 2; i < cats.length-1; i++) {
       //move the elements to the beginning so that the empty cell is at the end
       cats[i-1] = cats[i];
       cats[i] = null;
   }

   System.out.println(Arrays.toString(cats));
}
結論:

[Cat{name='Томас'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}, null]
見た目は良くなったように見えますが、これは安定した解決策とは言い難いです。少なくとも、配列から要素を削除するたびにこのコードを手動で記述する必要があるためです。悪い選択肢です。逆に、別のメソッドを作成することもできます。
public void deleteCat(Cat[] cats, int indexToDelete) {
   //...remove the cat by index and shift the elements
}
しかし、これもほとんど役に立ちません。このメソッドはオブジェクトに対してのみ機能しCat、他のメソッドに対しては機能しません。つまり、プログラム内に配列を使用するクラスがさらに 100 個ある場合、それぞれのクラスでまったく同じロジックを持つ同じメソッドを記述する必要があります。これは完全な失敗です -_- しかし、ArrayList クラスでは、この問題は正常に解決されています。要素を削除するための特別なメソッドを実装しますremove()
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Hippopotamus");
   Cat philipp = new Cat("Philip Markovich");
   Cat pushok = new Cat("Fluff");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(philipp);
   cats.add(pushok);
   System.out.println(cats.toString());

   cats.remove(1);

   System.out.println(cats.toString());
}
オブジェクトのインデックスをメソッドに渡すと、(配列の場合と同様に) 削除されました。この方法にはremove()2 つの特徴があります。 まず、「穴」が残りません。以前に手動で作成した、要素を途中から削除するときに要素を移動するロジックがすでに実装されています。コンソールで前のコードの出力を確認してください。

[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
[Cat{name='Томас'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
真ん中の猫1匹を外し、残りの猫を隙間ができないように移動させました。 次に、(通常の配列のように) インデックスによってオブジェクトを削除するだけでなく、オブジェクトへの参照によってもオブジェクトを削除できます。
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Hippopotamus");
   Cat philipp = new Cat("Philip Markovich");
   Cat pushok = new Cat("Fluff");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(philipp);
   cats.add(pushok);
   System.out.println(cats.toString());

   cats.remove(philipp);

   System.out.println(cats.toString());
}
結論:

[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Пушок'}]
これは、目的のオブジェクトのインデックスを常に頭の中に保持したくない場合に非常に便利です。通常の削除を整理したようです。ここで、次の状況を想像してみましょう。要素のリストを反復処理して、特定の名前の猫を削除したいと考えています。 このために、特別なループ演算子for-を使用しますfor eachこの講義でさらに詳しく学ぶことができます。
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Hippopotamus");
   Cat philipp = new Cat("Philip Markovich");
   Cat pushok = new Cat("Fluff");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(philipp);
   cats.add(pushok);

   for (Cat cat: cats) {

       if (cat.name.equals("Hippopotamus")) {
           cats.remove(cat);
       }
   }

   System.out.println(cats);
}
コードは非常に論理的であるように見えます。ただし、次のような結果に驚かれるかもしれません。

Exception in thread "main" java.util.ConcurrentModificationException
  at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
  at java.util.ArrayList$Itr.next(ArrayList.java:831)
  at Cat.main(Cat.java:25)
何らかのエラーが発生しており、なぜ突然表示されたのかは不明です。このプロセスには、対処する必要がある微妙な点が多数あります。覚えておく必要がある一般的なルール: コレクションを反復処理し、同時にその要素を変更することはできません。 はい、はい、まさに変更であり、単なる削除ではありません。コードで猫の削除を新しい猫の挿入に置き換えようとすると、結果は同じになります。
for (Cat cat: cats) {

   cats.add(new Cat("Salem Saberhegen"));
}

System.out.println(cats);

Exception in thread "main" java.util.ConcurrentModificationException
  at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
  at java.util.ArrayList$Itr.next(ArrayList.java:831)
  at Cat.main(Cat.java:25)
ある操作を別の操作に変更しましたが、結果は変わらず、同じエラーが発生しましたConcurrentModificationException。これはまさに、ルールを破ってリストを反復処理しているときにリストを変更しようとしたときに発生します。Java では、反復中に要素を削除するには、特別なオブジェクトであるイテレータ (クラスIterator) を使用する必要があります。このクラスは、Iterator要素のリストを安全に処理する責任があります。方法は 3 つだけなので非常に簡単です。
  • hasNext()-リスト内に次の要素があるかどうか、またはすでに最後の要素に到達しているかどうかに応じてどちらかをtrue返します。false
  • next()- リストの次の要素を返します
  • remove()- リストから要素を削除します
ご覧のとおり、イテレーターは文字通りニーズに合わせて「調整」されており、複雑なことは何もありません。たとえば、リストに次の要素が含まれているかどうかを確認し、含まれている場合はそれをコンソールに出力したいとします。
Iterator<Cat> catIterator = cats.iterator();//create an iterator
while(catIterator.hasNext()) {//as long as there are elements in the list

   Cat nextCat = catIterator.next();//get next element
   System.out.println(nextCat);// print it to the console
}
結論:

Cat{name='Томас'}
Cat{name='Бегемот'}
Cat{name='Фorпп Маркович'}
Cat{name='Пушок'}
ご覧のとおり、このクラスはArrayListイテレータを作成するための特別なメソッドをすでに実装しています - iterator()。また、イテレータを作成するときは、それが動作するオブジェクトのクラスを指定することに注意してください ( <Cat>)。最終的には、イテレーターを使用して元の問題を簡単に解決できます。たとえば、「Philip Markovich」という名前の猫を削除してみましょう。
Iterator<Cat> catIterator = cats.iterator();//create an iterator
while(catIterator.hasNext()) {//as long as there are elements in the list

   Cat nextCat = catIterator.next();//get next element
   if (nextCat.name.equals("Philip Markovich")) {
       catIterator.remove();//delete the cat with the desired name
   }
}

System.out.println(cats);
結論:

[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Пушок'}]
お気づきかもしれませんが、イテレータ メソッドでは要素インデックスも参照変数名も指定していませんremove()。この反復子は、見かけよりも賢いものです。このメソッドは、remove()反復子によって返された最後の要素を削除します。ご覧のとおり、必要なとおりに機能しました :) 基本的に、 から要素を削除することについて知っておくべきことはこれですべてですArrayList。より正確に言えば、ほぼすべてです。次の講義では、このクラスの「内部」を調べて、操作中にそこで何が起こっているのかを見ていきます :) では、また!
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION