Concurrent modification during iteration

3,727 views
Skip to first unread message

Dzenan Ridjanovic

unread,
Apr 25, 2013, 10:35:10 AM4/25/13
to mi...@dartlang.org
In Magic Boxes (https://github.com/dzenanr/magic_boxes) you may decide to delete selected boxes and lines. For example:

  List<Box> boxes;

  void deleteSelectedBoxes() {
    for (Box box in boxes) {
      if (box.isSelected()) {
       boxes.remove(box);
      }
    }
  }

The code produces the following error:

Concurrent modification during iteration: GrowableObjectArray.

How should I remove selected boxes without this error?

Kevin Moore

unread,
Apr 25, 2013, 10:37:33 AM4/25/13
to General Dart Discussion
void deleteSelectedBoxes() {
  var source = boxes.toList();
    for (Box box in source) {
      if (box.isSelected()) {
       boxes.remove(box);
      }
    }
  }


--
Consider asking HOWTO questions at Stack Overflow: http://stackoverflow.com/tags/dart
 
 

Kevin Moore

unread,
Apr 25, 2013, 10:38:01 AM4/25/13
to General Dart Discussion
Or better.

boxes.removeWhere((b) => b.isSelected());

Dzenan Ridjanovic

unread,
Apr 25, 2013, 10:53:17 AM4/25/13
to mi...@dartlang.org
Thanks Kevin!

boxes is a list: List<Box> boxes;
It is strange for me to read the code where I have to transform a list into a list!? But it works!

Iván Zaera Avellón

unread,
Apr 25, 2013, 10:55:12 AM4/25/13
to misc
It is not that you are transforming: you are making a copy to iterate over so that you remove in the other "original" copy.


2013/4/25 Dzenan Ridjanovic <dze...@gmail.com>

Jos Hirth

unread,
Apr 25, 2013, 10:56:08 AM4/25/13
to mi...@dartlang.org
for (int i = list.length - 1; i >= 0; --i) {
 
[...]
  // at the very end...
  if (list[i].someCondition()) {
    list
.removeAt(i);
 
}
}

You can remove elements if you iterate over the list in reverse and if you do the deletion at the very end of the loop's body. This way it doesn't matter if the elements, which follow the element you just removed, are shifted by one.

If the order doesn't need to be maintained, you can also do a somewhat cheaper swap/delete.

void unorderedDelete(List array, int index) {
 
var temp = array.removeLast();
 
if (index < array.length) {
    array
[index] = temp;
 
}
}

[...]

for (int i = list.length - 1; i >= 0; --i) {
 
[...]
 
// at the very end...
 
if (list[i].someCondition()) {
    unorderedDelete
(list, i);
 
}
}

Jos Hirth

unread,
Apr 25, 2013, 11:00:59 AM4/25/13
to mi...@dartlang.org
Kevin's version works because it creates a copy of that list. Basically, you're iterating over one list while deleting stuff from the other.

By the way, you can also filter the list down with where() or retainWhere()/removeWhere().

Iván Zaera Avellón

unread,
Apr 25, 2013, 11:00:56 AM4/25/13
to misc
That's what I usually do in Java: iterate backwards or take a copy of the list.

But having this beautiful construct (as Kevin noted):   


    boxes.removeWhere((b) => b.isSelected());


Who would want to do such arcane things? ;-)



2013/4/25 Jos Hirth <google...@kaioa.com>
--

Dzenan Ridjanovic

unread,
Apr 25, 2013, 3:17:23 PM4/25/13
to mi...@dartlang.org
Thank you all! I get it now.

Entaro Adun

unread,
Apr 26, 2013, 7:59:59 AM4/26/13
to mi...@dartlang.org
I think this is called the helloween effect. Because it was once discussed by some programmers on helloween? Iterate over a list while removing elements from the same list.

This will be a reoccurring problem:

  for (Box box in boxes) {
      if (box.isSelected()) {
       boxes.remove(box);
      }


The editor should give a warning when  itereting over a list while removing elements from the same list.

Reply all
Reply to author
Forward
0 new messages