使用删除在列表上循环[重复]

Posted

技术标签:

【中文标题】使用删除在列表上循环[重复]【英文标题】:loop on list with remove [duplicate] 【发布时间】:2010-12-27 15:00:38 【问题描述】:
    for (String fruit : list)
    
        if("banane".equals(fruit))
            list.remove(fruit);
        System.out.println(fruit);
    

这里有一个带有删除指令的循环。 在执行时,我在控制台输出下方得到了一些 ConcurrentModificationException:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)
at java.util.AbstractList$Itr.next(AbstractList.java:420)
at Boucle.main(Boucle.java:14)
abricot
banane

问题:如何使用循环删除某些元素?

【问题讨论】:

【参考方案1】:

您需要直接使用迭代器,并通过该迭代器删除项目。

for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) 
    String fruit = iterator.next();
    if ("banane".equals(fruit)) 
        iterator.remove();
    
    System.out.println(fruit);

【讨论】:

对于那些会认出自己的人:不要使用增量索引和 list.size() !我想用 foreach 循环更改代码,但这不是正确的解决方案。你的就是那个。 只需将it.hasNext() 更改为iterator.hasNext() 就完美了! (很明显......但谁知道......)【参考方案2】:

这似乎有点复杂,为什么不做一个普通的for循环呢?我认为它看起来更干净,不会抛出这个错误。如果您删除某些内容,只需贬低 i 即可。至少我的作品,无论如何。我想,这类自动循环更多是为了编码方便,所以如果它们不方便,那就不要使用它们。

for (int i = list.size() - 1; i>=0; i--) 
    String fruit = list.get(i);
    System.out.println(fruit);

    if ("banane".equals(fruit)) 
        list.remove(fruit);
    

【讨论】:

这在大列表上会非常慢(算法术语中的O(n^2)),因为List#remove(Object) 需要通过对给定对象的列表执行线性搜索来重做工作。如果可能,最好使用索引,这将使它成为O(n) 时间。【参考方案3】:

除了直接使用Iterator(我会推荐)之外,您还可以将要删除的元素存储在不同的列表中。

List<String> toRemove = new ArrayList<String>();
for (String fruit : list) 
    if ("banane".equals(fruit))
        toRemove.add(fruit);
    System.out.println(fruit);

for (String fruit : toRemove) 
    list.remove(fruit);

请注意,我不建议这样做,这只是一种选择。 :)

【讨论】:

是的。这就是为什么我会使用基于Iterator 的解决方案——这就是我所写的。 有不止一种方法可以做到,但大多数方法都是错误的;) “错误”也有不止一种含义。 :)【参考方案4】:

使用 for 循环,并以相反的顺序遍历集合。 (这意味着,从最后一个元素开始,然后循环到第一个元素。 通过这样做,您不会因为从集合中删除元素而更改索引而遇到问题。

您在发布的示例中遇到异常,因为您的迭代器迭代的列表已更改,这意味着迭代器变得无效。

【讨论】:

听起来很危险。内存不连续的双向链表之类的呢?我不知道lists et al在Java中是否有index,或者iterator是如何实现的,但是如果它像C++一样,如果你的方法适用于除ArrayList之外的任何东西,我会感到惊讶。【参考方案5】:
for(Iterator<String> iter = list.iterator(); iter.hasNext(); )

   String fruit = iter.next();
   if("banana".equals(fruit))
      iter.remove();
   System.out.println(fruit);

【讨论】:

【参考方案6】:

类似于 Bombe 的建议,但通过迭代列表副本,但从原始列表中删除,代码行数更少;

List<String> temp = new ArrayList<String>(list);
for (String fruit : temp)

    if("banane".equals(fruit))
        list.remove(fruit);
    System.out.println(fruit);

我个人认为这看起来比使用迭代器进行迭代更好。

【讨论】:

我会说这很容易出错.. 有 2 个列表,我们不需要第二个。只是我的 2 美分。 @cheekoo,我可以看到它会如何使用不必要的内存,但我看不出有能力的开发人员会如何使用这种方法引入错误。 哈哈!我同意。但是现在您已经开始使用条件语句了! “有能力的开发人员”;) 这有不必要的迭代。 new ArrayList(list) 将遍历 list。然后使用for 循环再次对其进行迭代。【参考方案7】:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
Iterator<String> iter = list.iterator();
while (iter.hasNext()) 
    String s = iter.next();

    if (s.equals("a")) 
        iter.remove();
    

是最好的方法..

【讨论】:

以上是关于使用删除在列表上循环[重复]的主要内容,如果未能解决你的问题,请参考以下文章

Python3基础 list 使用for循环 删除列表中的重复项

Python3基础 使用for循环 删除一个列表中的重复项

问题在for循环中删除列表项(python)[重复]

列表类型删除循环排序

在python中的单个列表上使用多个变量(for循环)[重复]

删除 C# 中重复的硬编码循环和条件