11

から特定の要素を削除しようとしていますArrayList<String>

for(int i=0; i<myList.size(); i++)
{
    if(myList.get(i).contains("foo"))
    {
        myList.remove(i);
    }
}

ただし、これにより、リストに「空のスペース」が残ります。リストで空の要素を除外し、繰り返し処理した後、必要なサイズに縮小したいと思います。

に切り替えることなくこれを行うスマートな方法はありLinkedListますか?

4

7 に答える 7

32

ただし、これにより、リストに「空のスペース」が残ります。

いいえ、そうではありません。リストからエントリを完全に削除します。他の要素は適切に移動されます。あなたが書いた方法で行うこと、次のエントリのチェックをスキップすることです...それは element になるように「シャッフルダウン」されるためiですが、次に element を調べますi + 1

これを回避する簡単な方法の 1 つは、代わりに逆方向に作業することです。

for (int i = myList.size() - 1; i >= 0; i--) {
    if (myList.get(i).contains("foo")) {
        myList.remove(i);
    }
}

もちろん、他の回答に記載されているようにイテレータを使用してください。どちらも機能します。ただし、複数のエントリを削除する場合は、上記のコードの方が少し効率的かもしれません。それが重要になることはまずありません。

残念ながら、イテレータ ソリューションを使用するには、イテレータを明示的に使用する必要があります。拡張 for ループを使用している間は、コレクションから削除することはできません。

于 2013-10-15T08:54:34.797 に答える
7

代わりにIteratorand 呼び出しを使用してください。Iterator.remove()

Iterator it = myList.iterator();
while(it.hasNext()) {
    if (it.next().contains("foo")) { 
        it.remove();
    }
}

このようにして、ループの終了条件としてリストに依存しながらリストのサイズを縮小し、変化する可能性のあるインデックスを使用してリストにアクセスするという問題も回避できます。

もちろん、リストを逆方向に繰り返すこともできます。

于 2013-10-15T08:54:54.530 に答える
3

あなたが探しているスマートな方法はIteratorインターフェースです。例えば:

Iterator<String> it = list.iterator();
while (it.hasNext()) {
   String nextItem = it.next();
   if (nextItem.contains("foo")) {
      it.remove();
   }
}
于 2013-10-15T08:55:02.813 に答える
2

ArrayList は、舞台裏で配列を維持します。と のソース コードを深く掘り下げたいと思いjava.util.ArrayListますjava.util.LinkedList

まず、ArrayList はバックグラウンドで配列を維持します。ArrayList インスタンスを作成すると、サイズが 10 の配列が作成され、要素が挿入されるとサイズが大きくなります。サイズは3(サイズ)/2+1まで伸びます

これがソースコードです。

arrat リストのデフォルト サイズ。コンストラクター コードを見てください。

public ArrayList() {
         this(10);
    }

そのサイズは 3(size)/2 + 1 になります。ソース コードは次のとおりです。ArrayList#ensureCapacityメソッドはArrayList#add内で呼び出されます

public void ensureCapacity(int minCapacity) {
         modCount++;
         int oldCapacity = elementData.length;
         if (minCapacity > oldCapacity) {
             Object oldData[] = elementData;
             int newCapacity = (oldCapacity * 3)/2 + 1;
             if (newCapacity < minCapacity)
                 newCapacity = minCapacity;
             // minCapacity is usually close to size, so this is a win:
             elementData = Arrays.copyOf(elementData, newCapacity);
        }
     }

ArrayList から項目を削除する場合。リストから削除され、他のリスト項目は削除された項目の場所に移動します。このオブジェクトへの参照は null に設定され、オブジェクトは GC の対象になりますが、ArrayList に割り当てられた参照がまだあることに注意してください。ArrayList の後ろの配列サイズは同じです。

ここにソースコードがあります

public E remove(int index) {
         rangeCheck(index);

        modCount++;
         E oldValue = elementData(index);

         int numMoved = size - index - 1;
         if (numMoved > 0)
             System.arraycopy(elementData, index+1, elementData, index,
                              numMoved);
         elementData[--size] = null; // Let gc do its work

         return oldValue;
     }

Jon Skeetが答えたように、アイテムが削除されると、削除されたアイテムの次のアイテムが削除されたアイテムの場所になります。

ただし、割り当てられたメモリ空間は削除後も同じです。java.util.LinkedList は、この問題を表しています。LinkedList 内のすべてのアイテムは、動的に割り当ておよび割り当て解除されます (もちろん、GC の作業です)。

java.util.LinkedList は、舞台裏で二重にリンクされたリストを維持します。追加操作と削除操作のたびに、LinkedList が使用するメモリ領域が変更されます。アイテムが削除され、前のアイテムと次のアイテムからのアイテムへの参照が更新されます。

ソースコードは次のとおりです。

private Entry<E> entry(int index) {
        if (index < 0 || index >= size)
           throw new IndexOutOfBoundsException("Index: "+index+
                                                ", Size: "+size);
        Entry<E> e = header;
        if (index < (size >> 1)) {
           for (int i = 0; i <= index; i++)
                e = e.next;
       } else {
            for (int i = size; i > index; i--)
                e = e.previous;
        }
       return e;
   }

GC は削除されるとすぐにアイテムを収集すると思いますが、確かではありません。ただし、削除されたメモリ ロケーションは GC の候補です。オブジェクトへの参照とオブジェクト自体に注意してください。

ArrayList と LinkedList の両方が項目を削除しますが、ArrayList はオブジェクト型の参照とプリミティブ型のメモリ空間を格納します。リンク リストも参照とメモリ空間を削除します。少なくとも、参照とメモリも GC の対象になります。

于 2013-10-15T09:57:31.210 に答える
1

リストを削除すると、自動的に縮小されます。

インデックス 3 の要素を削除すると、その要素が削除され、リストが縮小され、削除後にインデックス 4 にあった要素のインデックスが 3 になります。

これを行う必要があります:

for(int i=0; i<myList.size(); i++)
{
    if(myList.get(i).contains("foo"))
    {
        myList.remove(i);
        // as element is removed, next element will have decremented index
        i--;
    }
}
于 2013-10-15T08:59:30.067 に答える