2012-11-09 43 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<Pulse> iter = pulseArray.iterator(); 
while (iter.hasNext()) { 
    Pulse p = iter.next(); 
    if (p.getCurrent()==null) iter.remove(); 
} 

注意,Iterator#remove功能被认为是optionnal但由实施 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

从技术上讲,增强型for循环_is_使用迭代器。你能举一个他必须做的例子吗?另外,应该注意的是并不是所有的迭代器都会实际实现remove方法,并且会抛出一个'not implemented'异常。 –

+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

当你同一列表删除元素,指数受到干扰。尽量少如下不同:

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

使用迭代器会给你修改的列表,同时通过数组列表

2

迭代作为备选使用迭代器,你可以使用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)); 
1

没必要用迭代器。使用Java 8(流和过滤功能和lambda表达式),您可以使用一行完成它。 例如。所需的代码已经做了你所指定的操作将是:

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

这适用于我 –