简体   繁体   English

如果我们只删除 1 个元素,我们可以在迭代时删除吗?

[英]Could we remove while iterating if we just remove 1 element?

I have a list of custom objects.我有一个自定义对象列表。 I need to get/remove a specific object from that list but the equals implemented would not work based on what I need to search.我需要从该列表中获取/删除特定的 object,但是根据我需要搜索的内容,实现的equals将不起作用。
The following would work:以下将起作用:

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  

I was wondering if I could do the list.remove inside the for loop despite not using an iterator since the loop breaks immediately我想知道是否可以在for循环中执行list.remove ,尽管没有使用iterator ,因为循环立即中断

Using the delete(int) method in your loop will work just fine.在循环中使用delete(int)方法就可以了。

Your loop is closed so you have full control on i and you can use the list as you please.您的循环已关闭,因此您可以完全控制i并且您可以随意使用该列表。 You don't use i after having deleted the first element that matches, so there are no caveat.在删除第一个匹配的元素后,您不使用i ,因此没有警告。 If you were to reuse it, you would have to not increment it.如果要重用它,则不必增加它。

To avoid any trouble, the following if both more readable and expressive.为避免任何麻烦,以下内容更具可读性和表现力。 Also, it's totally implementation-agnostic.此外,它完全与实现无关。

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
}

There is no special program state associated with “being inside a for loop”.没有与“在 for 循环中”相关的特殊程序 state。 What matters, are the actions your program performs.重要的是您的程序执行的操作

So所以

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

is identical to等同于

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

as it performs the same actions (letting aside that the first variant will throw when no match has been found).因为它执行相同的操作(撇开第一个变体在找不到匹配项时会抛出)。 The differences regarding local variables defined in these code snippets are, well, local and do not affect anything outside the containing method.这些代码片段中定义的局部变量的差异是局部变量,不会影响包含方法之外的任何内容。

That said, the rule that you must not modify a collection (except through the iterator) while iterating over it, applies to iterator-based loops, where you are not in control of the iterator's internal state.也就是说,在迭代集合时不得修改集合(通过迭代器除外)的规则适用于基于迭代器的循环,您无法控制迭代器的内部 state。 When you are using an index based loop and fully understand the implications of removing an object at a particular index (of a random access list), you can even continue iterating.当您使用基于索引的循环并完全理解在(随机访问列表的)特定索引处删除 object 的含义时,您甚至可以继续迭代。 The important aspects, to do it correctly, are that the indices of all subsequent elements decrease by one when removing an element, further the size decreases so you must either, reread the size or decrement a previously cached size value.正确执行此操作的重要方面是,删除元素时所有后续元素的索引都会减少一个,进一步减小大小,因此您必须重新读取大小或减少先前缓存的大小值。

Eg, the following loop is valid例如,以下循环是有效的

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

But, of course, it's more idiomatic to use an Iterator or removeIf , as these approaches are not only easier to handle, they also work with other collections than random access lists.但是,当然,使用IteratorremoveIf更惯用,因为这些方法不仅更容易处理,而且它们也适用于其他 collections,而不是随机访问列表。 And especially removeIf may be more efficient when you remove more than one element.尤其是当您删除多个元素时, removeIf可能会更有效。

Just another way using streams,使用流的另一种方式,

    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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM