loops list遍历删除 - 调用在Java中的foreach循环中删除





list删除多个元素 foreach删除 (11)


for (String name : new ArrayList<String>(names)) {
    // Do something
    names.remove(nameToRemove);
}

在从原始列表中删除时,克隆列表names并遍历克隆。 比顶部的答案更清洁一点。

在Java中,使用foreach循环迭代集合时调用集合上的remove是否合法? 例如:

List<String> names = ....
for (String name : names) {
   // Do something
   names.remove(name).
}

作为附录,删除尚未迭代的项目是否合法? 例如,

//Assume that the names list as duplicate entries
List<String> names = ....
for (String name : names) {
    // Do something
    while (names.remove(name));
}



是的,您可以使用for-each循环,为此,您必须维护一个单独的列表来保存删除项目,然后使用removeAll()方法从名称列表中删除该列表,

List<String> names = ....

// introduce a separate list to hold removing items
List<String> toRemove= new ArrayList<String>();

for (String name : names) {
   // Do something: perform conditional checks
   toRemove.add(name);
}    
names.removeAll(toRemove);

// now names list holds expected values



使用

Interator或.remove()

使用

的CopyOnWriteArrayList




我不知道迭代器,但是直到今天,我在做的是从循环内的列表中删除元素:

List<String> names = .... 
for (i=names.size()-1;i>=0;i--) {    
    // Do something    
    names.remove(i);
} 

这总是有效的,可以用于其他语言或不支持迭代器的结构。




  1. 试试这个2.将条件改为“WINTER”,你会想知道:
public static void main(String[] args) {
  Season.add("Frühling");
  Season.add("Sommer");
  Season.add("Herbst");
  Season.add("WINTER");
  for (String s : Season) {
   if(!s.equals("Sommer")) {
    System.out.println(s);
    continue;
   }
   Season.remove("Frühling");
  }
 }



那些说你不能安全地从集合中除去通过Iterator的项目是不正确的,你可以使用ConcurrentHashMap之类的并发集合之一安全地执行它。




“增强for循环”的java设计是不将迭代器公开给代码,但安全删除一个项目的唯一方法是访问迭代器。 所以在这种情况下,你必须做到老派:

 for(Iterator<String> i = names.iterator(); i.hasNext();) {
       String name = i.next();
       //Do Something
       i.remove();
 }

如果在真正的代码中增强的for循环真的值得,那么您可以将这些项添加到临时集合中,并在循环之后调用列表中的removeAll。

编辑(补充):不,在iterator.remove()方法之外以任何方式更改列表时都会导致问题。 解决此问题的唯一方法是使用CopyOnWriteArrayList,但这确实是用于并发问题。

最便宜的(按照代码行)删除重复项的方法是将列表转储到LinkedHashSet(如果需要,然后返回到列表中)。 这可以在删除重复项时保留插入顺序。




你不想这样做。 它可能导致取决于集合的未定义行为。 你想直接使用Iterator 。 尽管每个构造都是语法糖,并且实际上正在使用迭代器,但它会将它从代码中隐藏起来,因此无法访问它来调用Iterator.remove

如果除了通过调用此方法以外的任何其他方式进行迭代时修改了底层集合,则未指定迭代器的行为。

请写下你的代码:

List<String> names = ....
Iterator<String> it = names.iterator();
while (it.hasNext()) {

    String name = it.next();
    // Do something
    it.remove();
}

请注意,代码调用Iterator.remove ,而不是List.remove

附录:

即使您要删除尚未迭代的元素,仍然不想修改集合,然后使用Iterator 。 它可能会以令人惊讶的方式修改集合,并影响Iterator未来操作。




在迭代时要安全地从集合中移除,你应该使用Iterator。

例如:

List<String> names = ....
Iterator<String> i = names.iterator();
while (i.hasNext()) {
   String s = i.next(); // must be called before you can call i.remove()
   // Do something
   i.remove();
}

Java文档

这个类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在迭代器创建后的任何时候,结构上都会修改列表,除了通过迭代器自己的remove或add方法以外,迭代器将抛出ConcurrentModificationException。 因此,面对并发修改,迭代器快速而干净地失败,而不是在将来某个未确定的时间冒着任意的,非确定性的行为风险。

也许很多新手不清楚的是,使用for / foreach构造迭代列表会隐式创建一个必须无法访问的迭代器。 这个信息可以在here找到




当您想从列表中移除元素时,最好使用Iterator

因为删除的源代码是

if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
             numMoved);
elementData[--size] = null;

所以,如果你从列表中删除一个元素,列表将被重新构造,另一个元素的索引将被改变,这可能会导致你想要发生的事情。




Python 2.7中访问循环内列表索引的最快方法是对小型列表使用range方法 ,对中型和大型列表使用枚举方法

请参阅以下代码示例中可用于迭代列表和访问索引值及其性能指标 (我认为对您有用)的不同方法:

from timeit import timeit

# Using range
def range_loop(iterable):
    for i in range(len(iterable)):
        1 + iterable[i]

# Using xrange
def xrange_loop(iterable):
    for i in xrange(len(iterable)):
        1 + iterable[i]

# Using enumerate
def enumerate_loop(iterable):
    for i, val in enumerate(iterable):
        1 + val

# Manual indexing
def manual_indexing_loop(iterable):
    index = 0
    for item in iterable:
        1 + item
        index += 1

请参阅以下每种方法的效果指标:

from timeit import timeit

def measure(l, number=10000):
print "Measure speed for list with %d items" % len(l)
print "xrange: ", timeit(lambda :xrange_loop(l), number=number)
print "range: ", timeit(lambda :range_loop(l), number=number)
print "enumerate: ", timeit(lambda :enumerate_loop(l), number=number)
print "manual_indexing: ", timeit(lambda :manual_indexing_loop(l), number=number)

measure(range(1000))
# Measure speed for list with 1000 items
# xrange:  0.758321046829
# range:  0.701184988022
# enumerate:  0.724966049194
# manual_indexing:  0.894635915756

measure(range(10000))
# Measure speed for list with 100000 items
# xrange:  81.4756360054
# range:  75.0172479153
# enumerate:  74.687623024
# manual_indexing:  91.6308541298

measure(range(10000000), number=100)
# Measure speed for list with 10000000 items
# xrange:  82.267786026
# range:  84.0493988991
# enumerate:  78.0344707966
# manual_indexing:  95.0491430759

因此,使用range方法是列出最快的1000个项目。 对于大小> 10 000项列表的列表是赢家。

添加以下一些有用的链接:







java loops iterator foreach