2012-11-09 13 views
7

特定の条件を満たす場合、JavaのArrayListから要素を削除したいと考えています。特定の条件に基づいてArrayListからオブジェクトを削除する

すなわち:

for (Pulse p : pulseArray) { 
    if (p.getCurrent() == null) { 
     pulseArray.remove(p); 
    } 
} 

これが動作しない理由を私は理解することができますが、これを行うには良い方法は何ですか?

+0

これは仕事に失敗するだけでなく、それは仕事をした場合でも、それはひどい性能を持つだろう。これはO(n^2)アルゴリズムです。なぜなら、配列のすべての要素を削除する必要があるからです。最適なアルゴリズムはO(n)です。 –

+0

@MarkByers "配列のすべての要素をチェックする"はO(n)ですが、なぜこれがO(n^2)だと思いますか? – jlordo

+0

@jlordo: 'list.remove(object)'はO(n)操作です。ループしているので、O(n)回実行されます。それはO(n * n)を与える。 –

答えて

11

あなたが反復するIteratorを使用する必要がありますし、(ないリストの)イテレータのremove機能:

Iterator#remove関数はoptionnalと言われている。なお
Iterator<Pulse> iter = pulseArray.iterator(); 
while (iter.hasNext()) { 
    Pulse p = iter.next(); 
    if (p.getCurrent()==null) iter.remove(); 
} 

それはを実現していますArrayListのイテレータ。

はこちらArrayList.javaからこの具体的な機能のコードです:あなたが反復しながら、それを使用する場合、それは例外をスローしない理由

765   public void remove() { 
766    if (lastRet < 0) 
767     throw new IllegalStateException(); 
768    checkForComodification(); 
769 
770    try { 
771     ArrayList.this.remove(lastRet); 
772     cursor = lastRet; 
773     lastRet = -1; 
774     expectedModCount = modCount; 
775    } catch (IndexOutOfBoundsException ex) { 
776     throw new ConcurrentModificationException(); 
777    } 
778   } 
779 
780   final void checkForComodification() { 
781    if (modCount != expectedModCount) 
782     throw new ConcurrentModificationException(); 
783   } 
784  } 

expectedModCount = modCount;線です。

+0

技術的には、イテレータを使用して、enhanced-for-loop _is_です。彼は何をしなければならないかの例を挙げることができますか?また、すべてのイテレータが実際にremoveメソッドを実装するわけではなく、実装されていない例外がスローされることに注意してください。 –

+0

@ Clockwork-Museはい、内部ArrayListのイテレータはそれを実装しています。 –

0

コレクションのメソッドを使用して、反復処理中のコレクションを変更することはできません。ただし、イテレータ(ArrayListのイテレータを含む)の中には、イテレートする順序でメソッドを削除できるようにするremove()メソッドがあります。

Iterator<Pulse> iterator = pulseArray.iterator(); 
while (iterator.hasNext()) { 
    Pulse p = iterator.next(); 
    if (p.getCurrent() == null) { 
    iterator.remove(); 
    } 
} 
0

あなたは同じリストから要素を削除するある場合は、インデックスが乱れます。別々に以下のように少しを試してみてください:Iteratorを使用すると、あなたのイテレータを使用する代替としてのArrayListを通じて

-1

、あなたはGuavaコレクションライブラリを使用することができます。 (あなたがそういったことにしている場合)これはfunctional以上であることの利点を持っていない:

Predicate<Pulse> hasCurrent = new Predicate<Pulse>() { 
    @Override public boolean apply(Pulse input) { 
    return (input.getCurrent() != null); 
    } 
}; 

pulseArray = Lists.newArrayList(Collections2.filter(pulseArray, hasCurrent)); 
2

を反復しながら、リストを変更する力を与えるだろう

for (int i=0; i < pulseArray.size(); i++) { 
    Pulse p = (Pulse)pulseArray.get(i); 
    if (p.getCurrent() == null) { 
     pulseArray.remove(p); 
     i--;//decrease the counter by one 
    } 
    } 
1

イテレータを使用する必要が。 Java 8(ストリーミングとフィルタリング機能とlambda)を使用すると、1行で実現できます。 たとえば、あなたが指定した操作が可能になるん必要なコード:

pulseArray = pulseArray.stream().filter(pulse -> pulse != null).collect(Collectors.toList()); 
+2

新しいリストを作成するのではなく、 'removeIf'を使うべきです... – assylias

+0

' Objects :: nonNull'を使うこともできます。 – shmosel

1

あなたがここに、Collection::removeIf(Predicate filter)を使用することができますが、簡単な例です:

final Collection<Integer> list = new ArrayList<>(Arrays.asList(1, 2)); 
list.removeIf(value -> value < 2); 
System.out.println(list); // outputs "[2]" 
+0

これは私のために働く –

関連する問題