使用 For 循环从 ArrayList 中删除数据

Posted

技术标签:

【中文标题】使用 For 循环从 ArrayList 中删除数据【英文标题】:Delete data from ArrayList with a For-loop 【发布时间】:2012-05-31 02:30:41 【问题描述】:

我遇到了一个奇怪的问题。 我以为这会花费我几分钟,但我现在挣扎了几个小时...... 这是我得到的:

for (int i = 0; i < size; i++)
    if (data.get(i).getCaption().contains("_Hardi"))
        data.remove(i);
    

dataArrayList. 在 ArrayList 中,我得到了一些字符串(总共 14 个左右),其中 9 个字符串的名称为 _Hardi。

使用上面的代码,我想删除它们。 如果我 replace data.remove(i);System.out.println 会打印 9 次,这很好,因为 _Hardi 在 ArrayList 中出现了 9 次。

但是当我使用data.remove(i); 时,它不会删除所有 9 个,而只会删除一些。 我做了一些测试,我也看到了这个:

当我将字符串重命名为: 哈迪1 哈迪2 哈迪3 哈迪4 哈迪5 哈迪6

然后它只删除偶数(1、3、5 等)。 他一直在跳过 1,但不知道为什么。

如何解决这个问题?或者也许是另一种删除它们的方法?

【问题讨论】:

【参考方案1】:

这里的问题是您正在迭代从 0 到 size 并且在循环内您正在删除项目。删除项目将减小列表的大小,当您尝试访问大于有效大小(删除项目后的大小)的索引时,列表将失败。

有两种方法可以做到这一点。

如果不想处理索引,请删除使用迭代器

for (Iterator<Object> it = data.iterator(); it.hasNext();) 
if (it.next().getCaption().contains("_Hardi")) 
    it.remove();


否则,从末尾删除。

for (int i = size-1; i >= 0; i--)
    if (data.get(i).getCaption().contains("_Hardi"))
            data.remove(i);
    
 

【讨论】:

谢谢你,也谢谢你的解释。现在我也知道为什么它总是跳过了。 如果我像data = new ArrayList&lt;&gt;()一样重新初始化会怎样 从末尾删除部分非常好【参考方案2】:

您不应该在迭代列表时从列表中删除项目。相反,请使用Iterator.remove(),例如:

for (Iterator<Object> it = list.iterator(); it.hasNext();) 
    if ( condition is true ) 
        it.remove();
    

【讨论】:

请注意,it.next() 必须被调用。有无条件。【参考方案3】:

每次删除一个项目时,都会更改它前面的项目的索引(因此,当您删除 list[1] 时,list[2] 变为 list[1],因此跳过。

这是一个非常简单的方法:(倒计时而不是倒计时)

for(int i = list.size() - 1; i>=0; i--) if(condition...) list.remove(i);

【讨论】:

【参考方案4】:

这是因为当您从列表中删除一个元素时,列表的元素会向上移动。因此,如果您删除第一个元素,即索引 0 处的元素,则索引 1 处的元素将移动到索引 0,但您的循环计数器将在每次迭代中不断增加。因此,您没有获得更新的第 0 个索引元素,而是获得了第 1 个索引元素。因此,每次从列表中删除一个元素时,只需将计数器减一即可。

您可以使用以下代码使其正常工作:

for (int i = 0; i < data.size(); i++)
    if (data.get(i).getCaption().contains("_Hardi"))
        data.remove(i);
        i--;
    

【讨论】:

【参考方案5】:

如果您仔细考虑一下,那将是非常有意义的。假设您有一个列表[A, B, C]。第一次通过循环,i == 0。您会看到元素 A,然后将其删除,因此列表现在为 [B, C],元素 0 为 B。现在你在循环结束时增加i,所以你看到的是list[1],即C

一种解决方案是每当您删除一个项目时减少i,以便它“取消”随后的增量。正如上面 matt b 所指出的,一个更好的解决方案是使用具有内置 remove() 函数的 Iterator&lt;T&gt;

一般来说,当遇到这样的问题时,拿出一张纸并假装自己是计算机,这是一个好主意——遍历循环的每一步,写下所有变量走。那会让“跳过”变得清晰。

【讨论】:

【参考方案6】:

我不明白为什么这个解决方案对大多数人来说是最好的。

for (Iterator<Object> it = data.iterator(); it.hasNext();) 
    if (it.next().getCaption().contains("_Hardi")) 
        it.remove();
    

第三个参数是空的,因为已经移到下一行。此外it.next() 不仅增加循环的变量,还用于获取数据。对我来说,使用 for 循环具有误导性。为什么不使用while

Iterator<Object> it = data.iterator();
while (it.hasNext()) 
    Object obj = it.next();
    if (obj.getCaption().contains("_Hardi")) 
            it.remove();
    

【讨论】:

【参考方案7】:

因为一旦你删除一个值,你的索引就不好了

此外,您将无法访问size,因为如果您删除一个元素,则大小会发生变化。

您可以使用iterator 来实现。

【讨论】:

【参考方案8】:
for (Iterator<Object> it = data.iterator(); it.hasNext();) 
    if ( it.getCaption().contains("_Hardi")) 
        it.remove(); // performance is low O(n)
    

如果您的删除操作在列表中需要很多。最好使用 LinkedList,它提供更好的性能 Big O(1)(大致)。

ArrayList 中的性能是O(n)(大致)。因此对删除操作的影响非常大。

【讨论】:

【参考方案9】:

虽然晚了,但可能对某人有用。

Iterator<YourObject> itr = yourList.iterator();

// remove the objects from list
while (itr.hasNext())

    YourObject object = itr.next();
    if (Your Statement) // id == 0
    
        itr.remove();
    

【讨论】:

【参考方案10】:

除了现有答案之外,您还可以使用带有条件增量的常规 while 循环:

int i = 0;
while (i < data.size()) 
    if (data.get(i).getCaption().contains("_Hardi"))
        data.remove(i);
    else i++;

注意 data.size() 必须在循环条件中每次都被调用,否则你最终会得到一个 IndexOutOfBoundsException,因为删除的每一项都会改变列表的原始大小。

【讨论】:

【参考方案11】:

发生这种情况是因为删除元素会修改ArrayList 的索引。

【讨论】:

【参考方案12】:
import java.util.ArrayList;

public class IteratorSample 

    public static void main(String[] args) 
        // TODO Auto-generated method stub

        ArrayList<Integer> al = new ArrayList<Integer>();
        al.add(1);
        al.add(2);      
        al.add(3);
        al.add(4);

        System.out.println("before removal!!");
        displayList(al);

        for(int i = al.size()-1; i >= 0; i--)
            if(al.get(i)==4)
                al.remove(i);
            
        

        System.out.println("after removal!!");
        displayList(al);


    

    private static void displayList(ArrayList<Integer> al) 
        for(int a:al)
            System.out.println(a);
        
    


输出:

删除前!! 1 2 3 4

删除后!! 1 2 3

【讨论】:

【参考方案13】:

有一种更简单的方法可以解决这个问题,而无需创建新的迭代器对象。这是概念。假设您的 arrayList 包含一个名称列表:

names = [James, Marshall, Susie, Audrey, Matt, Carl];

要删除 Susie 的所有内容,只需获取 Susie 的索引并将其分配给一个新变量:

int location = names.indexOf(Susie);//index equals 2

现在你有了索引,告诉 java 计算你想从 arrayList 中删除值的次数:

for (int i = 0; i < 3; i++)  //remove Susie through Carl
    names.remove(names.get(location));//remove the value at index 2

每次循环值运行时,arrayList 的长度都会减少。由于您已经设置了一个索引值并且正在计算删除值的次数,所以您已经设置好了。以下是每次通过后的输出示例:

                           [2]
names = [James, Marshall, Susie, Audrey, Matt, Carl];//first pass to get index and i = 0
                           [2]
names = [James, Marshall, Audrey, Matt, Carl];//after first pass arrayList decreased and Audrey is now at index 2 and i = 1
                           [2]
names = [James, Marshall, Matt, Carl];//Matt is now at index 2 and i = 2
                           [2]
names = [James, Marshall, Carl];//Carl is now at index 3 and i = 3

names = [James, Marshall,]; //for loop ends

这是您的最终方法的外观:

public void remove_user(String name) 
   int location = names.indexOf(name); //assign the int value of name to location
   if (names.remove(name)==true) 
      for (int i = 0; i < 7; i++) 
         names.remove(names.get(location));
      //end if
      print(name + " is no longer in the Group.");
//end method

【讨论】:

【参考方案14】:

这是使用 Arraylist 时的常见问题,它发生的原因是 Arraylist 的长度(大小)可以改变。删除时,大小也会发生变化;所以在第一次迭代之后,你的代码就乱套了。最好的建议是使用 Iterator 或从后面循环,不过我会推荐 backword 循环,因为我认为它不那么复杂,而且它仍然适用于许多元素:

//Let's decrement!
for(int i = size-1; i >= 0; i--)
    if (data.get(i).getCaption().contains("_Hardi"))
        data.remove(i);
    
 

还是你的旧代码,只是循环方式不同!

我希望这会有所帮助...

编码愉快!!!

【讨论】:

以上是关于使用 For 循环从 ArrayList 中删除数据的主要内容,如果未能解决你的问题,请参考以下文章

ArrayList循环删除报错Exception in thread “main“ java.util.ConcurrentModificationException

一个ArrayList在循环过程中删除,会不会出问题,为什么?

使用循环从字符数组列表中删除重复项? [复制]

C++ STL容器在for循环中删除迭代器 正确方法 it++正确吗

C++ STL容器在for循环中删除迭代器 正确方法 it++正确吗

ArrayList的删除姿势你都知道了吗