English 中文(简体)
从带有 For-loop 的矩阵列表中删除数据
原标题:Delete data from ArrayList with a For-loop

I got a weird problem. I thought this would cost me few minutes, but I am struggling for few hours now... Here is what I got:

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

The data is the ArrayList. In the ArrayList I got some strings (total 14 or so), and 9 of them, got the name _Hardi in it.

And with the code above I want to remove them. If I replace data.remove(i); with a System.out.println then it prints out something 9 times, what is good, because _Hardi is in the ArrayList 9 times.

But when I use data.remove(i); then it doesn t remove all 9, but only a few. I did some tests and I also saw this:

When I rename the Strings to: Hardi1 Hardi2 Hardi3 Hardi4 Hardi5 Hardi6

Then it removes only the on-even numbers (1, 3, 5 and so on). He is skipping 1 all the time, but can t figure out why.

如何修补呢 或者换个方法除掉它们?

最佳回答

这里的问题是, 您正在从 0 滚动 < strong > 到 大小, 并且正在循环中删除项目 < / strong > 。 删除项目将会减少列表的大小, 当您尝试访问大于有效大小( 被删除的项目之后的大小) 的索引时, 列表的大小将会失效 。

这样做有两种方法。 < / strong>

如果您不想处理索引, 请删除“ 强” 。

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

Else, 从结尾处删除 < strong > 。

for (int i = size-1; i >= 0; i--){
    if (data.get(i).getCaption().contains("_Hardi")){
            data.remove(i);
    }
 }
问题回答

您在转动时不应从列表中删除项目。 相反, 请使用 < code> Iterator. remove () 例如 :

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

每次删除一个项目时,您都在修改其前面的项目的索引(因此,当您删除列表[1] 时,列表[2] 成为列表[1],因此跳过 。

在这里,一个非常容易的方式围绕它:(倒数而不是上调)


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

这是因为当您从列表中删除一个元素时,列表元素向上移动。因此,如果在索引 0 中删除第一个元素, 索引 1 中的元素将被移到索引 0, 但循环计数器会在每个迭代中继续增加。 因此, 不再获取更新后的 0 指数元素, 你就会得到第一个索引元素。 所以, 每次从列表中删除一个元素时, 只需将一个计数器减少一个即可 。

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

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

如果您想通的话, 完全合理 。 假设您有一个列表 < code> [A、 B、 C] 。 浏览该循环的第一个通道, < code > i = 0 < / code > 。 您看到元素 < code> A < / code >, 然后删除它, 因此列表现在是 < code> [B、 C] , 元素 0 正在 < code> B/ code > 。 现在您在循环结尾处加注 < code> > < / code >, 所以您可以重新查看 < code> list [1] < / code >, 也就是 < code > <, C

一种解决办法是,当您删除一个项目时,将 < code> > i 降为衰减,以便“ 取消” 随后的递增。如上文mattb指出的,更好的解决办法是使用 < code> Iterator<T> ,它具有 < code> remove () 的内置功能。

一般说来,当面对这样的问题时, 拿出一张纸来装作电脑-- 穿过环形的每一个步骤, 写下所有变量。 这会让“ 滑板” 变得清晰。

我不明白为什么这一解决办法对大多数人来说是最好的。

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

第三个参数是空的, 因为已被移动到下一行 。 此外, < code>it. next () 不仅用于递增循环变量, 而且还用于获取数据 。 对于我来说, < code> for 循环使用有误导性 。 为什么您不使用 < code > 而不使用 ?

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

因为删除一个值后你的索引就不再好

此外,您无法进入 size ,因为如果删除一个元素,则大小随变。

您可以使用 < code> 编辑 实现此目标。

for (Iterator<Object> it = data.iterator(); it.hasNext();) {
    if ( it.getCaption().contains("_Hardi")) {
        it.remove(); // performance is low O(n)
    }
}

如果您的删除操作在列表中需要很多内容。 您最好使用 < strong > LinkedList , 也就是 提供更好的性能 Big < code>O(1) (粗略) 。

在 ArrayList 性能为 O(n) (粗略) 的地方。 因此, 移除操作的影响非常大 。

使用阵列列表时,这是一个常见的问题。 这是因为阵列列表的长度( 大小) 可以改变。 在删除时, 大小也会改变; 所以在第一次迭代后, 您的代码会变得干燥。 最好的建议是要么使用 Exerator, 要么从后面回转, 我会推荐后词环, 不过因为我认为它不太复杂, 而且仍然对很多元素有效 :

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

还是你的旧代码, 唯一的循环不同!

我希望这能帮上忙...

编码快乐!

已经很晚了,但可能对某人有用

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

// remove the objects from list
while (itr.hasNext())
{
    YourObject object = itr.next();
    if (Your Statement) // id == 0
    {
        itr.remove();
    }
}

除了现有的答案外,您还可以使用定期循环和有条件加薪的循环:

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

请注意,在环状状态下每次必须调用 data. size () , 否则最后会有一个 < code> IndexOutobsBoundsExpension , 因为每次删除的项目都会改变您原来的列表大小 。

这是因为通过删除元素来修改 ArrayList 的索引。

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);
        }
    }

}

输出 :

before removal!! 1 2 3 4

after removal!! 1 2 3

在不创建新的迭代器对象的情况下,解决这个问题的方法比较容易。这里是这个概念。假设您的数组列表包含一个名称列表:

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

要从 Susie 前方删除一切, 只需获得 Susie 索引, 并将其指定为新变量 :

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

如果您有了索引, 请告诉 java 计算您想要从数组列表中删除值的次数 :

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

每次循环值运行时,数组列表会缩短长度。由于您已经设置了索引值,并且正在计算删除值的次数,请全部设置。这里是每次通过后输出的示例:

                           [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




相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...