Is it possible to iterate between two iterators of a same list and remove an item within the nested iterator?
Version 1 (does not work):
var i = all.iterator(); while (i.hasNext()) { var a = i.next(); var j = all.iterator(); while (j.hasNext()) { var b = j.next(); if (!a.shouldBRemoved(b)) { a.setDuplicates(a.getDuplicates + 1); // I want to remove the element on the fly // because on each iteration the iterated elements will have a decreased size and will iterate faster (because of fewer elements) // However: this does NOT work because of ConcurrentModificationException: j.remove(); } }
}
I get a java.util.ConcurrentModificationException
, because I modify an element within the same iterator..
I can solve this issue by using another list removableItems
and put those items in it:
Version 2 (works):
for (var a : all) { for (var b : all) { if (!a.shouldBRemoved(b)) { a.setDuplicates(a.getDuplicates + 1); // this works, // however I must use an additation list to keep track of the items to be removed // it's also not more performant than removing the elements on the fly // because on each iteration the iterated elements has the same size removableItems.add(b); } } } all.removeAll(removableItems);
Is there a way to solve this without needing an intermediate list removableItems
? I want to remove the element on the fly.
Advertisement
Answer
I found a good solution so far (Version 3):
List<Item> removeDuplicates(List<Item> all) { var uniqueResults = new ArrayList<Item>(); for (var a : all) { for (var b : all) { // check if "a" and "b" is not the same instance, but have equal content if (!a.equals(b) && a.isDeepEqualTo(b)) { if (a.duplicates == 0 && b.duplicates == 0) { // "a" has duplicates: // Add only "a" and discard "b" for the rest of the loops. uniqueResults.add(a); } // count the number of duplicates a.duplicates = a.duplicates + 1; } } // "a" has no duplicates, add it. if (a.duplicates == 0 && !uniqueResults.contains(a)) { uniqueResults.add(a); } } return uniqueResults; }
It works so far – I don’t see any edge cases where this would wrongly (not) remove.
It’s also better than using version 2 (with its removableItems()
-list) as this is more performant (especially for huge lists) because we do not use remove
or removAll
, we only add items (which has O(1)).