【问题标题】:Could we remove while iterating if we just remove 1 element?如果我们只删除 1 个元素,我们可以在迭代时删除吗?
【发布时间】:2020-06-23 09:05:55
【问题描述】:

我有一个自定义对象列表。我需要从该列表中获取/删除特定对象,但根据我需要搜索的内容,实现的 equals 不起作用。
以下将起作用:

int index = -1;  
for(int i = 0; i < list.size(); i++) {
  if(list.get(i).getAttr().equals(arg)) {
     index = i;  
     break;  
  }  
}    
CustomObject = list.remove(index);  
// use CustomObject here  

我想知道我是否可以在for 循环中执行list.remove,尽管没有使用iterator,因为循环会立即中断

【问题讨论】:

  • 何不试试看呢?
  • @Michael:因为list 是作为接口传递的,所以我不想做一个适用于例如的解决方案。那个版本的java中的ArrayList
  • 好的,那么是什么阻止您尝试使用 4 个主要的 List 实现,并将这些发现作为您的问题的基础?
  • 是的。您也可以使用list.removeIf((a)-&gt;a.getAttr().equals(arg));,但这会删除所有满足条件的元素,而不仅仅是第一个。

标签: java list collections


【解决方案1】:

在循环中使用delete(int) 方法就可以了。

您的循环已关闭,因此您可以完全控制i,您可以随意使用该列表。在删除第一个匹配的元素后,您不使用i,因此没有警告。如果要重用它,则必须增加它。

为避免任何麻烦,以下内容更具可读性和表现力。此外,它完全与实现无关。

CustomObject deletedObject = null;
for (Iterator<CustomObject> i = list.iterator(); i.hasNext(); ) {
  CustomObject candidate = i.next();
  if (candidate.getAttr().equals(arg)) {
    deletedObject = candidate;
    i.remove();
    break;
  }
}
if (deletedObject != null) {
  // Do something with deletedObject
}

【讨论】:

  • 我还需要另一个变量,对吧?因为我不能像object = list.remove(index)那样做object = i.remove()
  • @Jim 正确。考虑到这一点,我更新了答案。
【解决方案2】:

没有与“在 for 循环中”相关的特殊程序状态。重要的是您的程序执行的操作

所以

int index = -1;
for(int i = 0; i < list.size(); i++) {
    if(list.get(i).getAttr().equals(arg)) {
        index = i;
        break;
    }
}
CustomObject o = list.remove(index);
// use CustomObject here

等同于

for(int i = 0; i < list.size(); i++) {
    if(list.get(i).getAttr().equals(arg)) {
        CustomObject o = list.remove(i);
        // use CustomObject here
        break;
    }
}

因为它执行相同的操作(撇开第一个变体在找不到匹配项时会抛出)。这些代码 sn-ps 中定义的局部变量的区别是,local,并且不会影响包含方法之外的任何内容。

也就是说,在迭代集合时不得修改集合(通过迭代器除外)的规则适用于基于迭代器的循环,您无法控制迭代器的内部状态。当您使用基于索引的循环并完全理解删除特定索引处的对象(随机访问列表)的含义时,您甚至可以继续迭代。正确执行此操作的重要方面是,删除元素时所有后续元素的索引都会减少 1,大小会进一步减小,因此您必须重新读取大小或减少先前缓存的大小值。

例如,下面的循环是有效的

for(int i = 0; i < list.size(); i++) {// rereads size on each iteration
    if(list.get(i).getAttr().equals(arg)) {
        CustomObject o = list.remove(i--); // decrease index after removal
        // use CustomObject here
        // continue
    }
}

但是,当然,使用IteratorremoveIf 更为惯用,因为这些方法不仅更易于处理,而且还可以与随机访问列表以外的其他集合一起使用。尤其是removeIf,当您删除多个元素时可能会更有效。

【讨论】:

    【解决方案3】:

    使用流的另一种方式,

        List<String> str1 = new ArrayList<String>();
        str1.add("A");
        str1.add("B");
        str1.add("D");
        str1.add("D");
    
        Optional<Object> foundVal = str1.stream().filter(s -> 
                s.contains("D")).findFirst().map(val -> {
                                                 str1.remove(val);
                                                 return val;
                                                 });
    
    
        System.out.println(str1);
        System.out.print(" " + foundVal.get());
    
    Output
    
    [A, B, D]  D
    

    【讨论】:

      猜你喜欢
      • 2016-05-05
      • 1970-01-01
      • 2019-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-10
      相关资源
      最近更新 更多