14

我有以下代码-

import java.util.ArrayList;

public class ArrayListExp{
    public static void main (String[] args){

        ArrayList<String> name = new ArrayList<String>();

        name.add("Chris");
        name.add("Lois");
        name.add("Meg");
        name.add("Meg");
        name.add("Brain");
        name.add("Peter");
        name.add("Stewie");

        System.out.println(name);

        for ( int i = 0;  i < name.size(); i++){
            String oldName = name.get(i);
            if(oldName.equals("Meg"))
            {
                name.remove(i);
            }
        }

        System.out.println(name);
    }
}

但在这里它给了我输出 -

[Chris, Lois, Meg, Meg, Brain, Peter, Stewie]
[Chris, Lois, Meg, Brain, Peter, Stewie]

我没有明白这一点,为什么这没有删除Meg,但我只尝试了一个Meg,在这种情况下它正在工作。当我Meg最后添加几个时,我Meg没有从ArrayList. 为什么?

4

7 回答 7

25

当您删除第一个“Meg”时,索引i=2. 然后它会增加,但由于“Meg”之一已经被删除,现在name.get(3)是“Brain”。所以你实际上并没有检查第二个“Meg”。

解决问题。您可以在删除元素时减少索引:

public class ArrayListExp{
    public static void main (String[] args){

        ArrayList<String> name = new ArrayList<String>();

        name.add("Chris");
        name.add("Lois");
        name.add("Meg");
        name.add("Meg");
        name.add("Brain");
        name.add("Peter");
        name.add("Stewie");

        System.out.println(name);

        for ( int i = 0;  i < name.size(); i++){
            String oldName = name.get(i);
            if(oldName.equals("Meg"))
            {
                name.remove(i);
                i--;
            }
        }

        System.out.println(name);
    }
}
于 2013-10-19T02:22:50.000 回答
7

您正在迭代第一个Meg,当它Meg被删除时,数组值会移动一个。

[Chris, Lois, Meg, Meg, Brain, Peter, Stewie]
   0     1     2    3     4      5       6

FirstMeg被删除,循环递增 i 因为它完成了 for 循环内的所有内容的执行,所以i现在将是 3 并且数组已被修改:

[Chris, Lois, Meg, Brain, Peter, Stewie]
   0     1     2     3      4      5      

尝试向后迭代。

for ( int i = name.size() - 1;  i >= 0; i--){
    String oldName = name.get(i);
    if(oldName.equals("Meg"))
    {
        name.remove(i);
    }
}
于 2013-10-19T02:26:49.853 回答
4

您可以使用name.removeAll(Arrays.asList("Meg"));删除所有"Meg"

您的完整代码将是

for ( int i = 0;  i < name.size(); i++){
    String oldName = name.get(i);
    if(oldName.equals("Meg"))
    {
       name.removeAll(Arrays.asList("Meg"));
    }
}
于 2013-10-19T02:32:24.710 回答
1

您在从 0 到 N 迭代时从 ArrayList 中删除,因此当您删除索引 N 处的第一个 Meg 时,下一个 Meg 向下移动到索引 N,然后将 i 增加到 N+1。所以第二个梅格不会被删除。尝试以相反的顺序迭代(N 到 0):

for ( int i = name.size() - 1;  i >= 0; i--) {
于 2013-10-19T02:22:46.400 回答
1

这是因为当 i=2 并且条件为真时,删除 meg 并且所有索引都向上移动。因此接下来我将指向 Brain,而不是 meg。

尝试这个。(如果条件成立,则将 i 减一)

for ( int i = 0;  i < name.size(); i++){
            String oldName = name.get(i);
            if(oldName.equals("Meg"))
            {
                name.remove(i);
                i--;
            }
        }
于 2013-10-19T02:24:05.877 回答
0

删除元素时不应使用 for 循环。在实现某些逻辑时总是会出现问题。为您的问题使用反向 for 循环,并始终尝试为每个循环使用。

于 2013-10-19T02:26:38.520 回答
0

Java 8+

Collection接口现在提供了一个removeIf方法来修改它,您可以向该方法提供一个谓词,true如果元素应该被删除,则返回该谓词。

因此,您可以像这样使用 lambda:

name.removeIf(name -> name.equals("Meg"));

为了更简洁,也可以使用方法引用。如果有null元素,以下代码也将起作用。

name.removeIf("Meg"::equals);

如果您不想修改旧列表,可以使用Streamandfilter来获取List所有应保留的项目中的一个,方法是否定条件。

final List<String> filtered = name.stream()
      .filter(name -> !"Meg".equals(name))
      .collect(Collectors.toList());

如果您特别需要ArrayList, 请改用Collectors.toCollection构造函数引用。

final ArrayList<String> filtered = name.stream()
       .filter(name -> !"Meg".equals(name))
       .collect(Collectors.toCollection(ArrayList::new));

前 Java 8

问题是 ArrayList 在被迭代时正在被修改,这会改变它的大小并将后面的元素向前移动;如果有需要删除的连续元素,这是一个问题。每次删除一个元素时,您都需要将索引减一,因为该索引现在将引用下一个元素。

for (int i = 0; i < name.size(); i++) {
    String oldName = name.get(i);
    if (oldName.equals("Meg")) {
        name.remove(i);
        i--;//Important!
    }
}

向后循环也可以解决这个问题,因为元素永远不会移动到尚未检查的位置。
for (int i = name.size() - 1; i >= 0; i--) {
    String oldName = name.get(i);
    if (oldName.equals("Meg")) {
        name.remove(i);
    }
}

一般来说,使用 anIterator最适合这种操作,因为它支持在迭代调用时删除元素Iterator#remove。这也修改了List原地。对于更复杂的操作,请考虑使用ListIterator.

final Iterator<String> it = name.iterator();
while(it.hasNext()){
    final String name = it.next();
    if(name.equals("Meg")){
         it.remove();
    }
}
于 2020-07-17T19:03:35.573 回答