Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing items from a collection in java while iterating over it

I want to be able to remove multiple elements from a set while I am iterating over it. Initially I hoped that iterators were smart enough for the naive solution below to work.

Set<SomeClass> set = new HashSet<SomeClass>(); fillSet(set); Iterator<SomeClass> it = set.iterator(); while (it.hasNext()) {     set.removeAll(setOfElementsToRemove(it.next())); } 

But this throws a ConcurrentModificationException.

Note that iterator.remove() will not work as far as I can see because I need to remove multiple things at a time. Also assume that it is not possible to identify which elements to remove "on the fly", but it is possible to write the method setOfElementsToRemove(). In my specific case it would take up a lot of memory and processing time to determine what to remove while iterating. Making copies is also not possible because of memory constraints.

setOfElementsToRemove() will generate some set of SomeClass instances that I want to remove, and fillSet(set) will fill the set with entries.

After searching Stack Overflow I could not find a good solution to this problem but a few hours break later I realized the following would do the job.

Set<SomeClass> set = new HashSet<SomeClass>(); Set<SomeClass> outputSet = new HashSet<SomeClass>(); fillSet(set); while (!set.isEmpty()) {     Iterator<SomeClass> it = set.iterator();     SomeClass instance = it.next();     outputSet.add(instance);     set.removeAll(setOfElementsToRemoveIncludingThePassedValue(instance)); } 

setOfElementsToRemoveIncludingThePassedValue() will generate a set of elements to remove that includes the value passed to it. We need to remove the passed value so set will empty.

My question is whether anyone has a better way of doing this or whether there are collection operations that support these kind of removals.

Also, I thought I would post my solution because there seems to be a need and I wanted to contribute the the excellent resource that is Stack Overflow.

like image 213
nash Avatar asked Nov 04 '09 16:11

nash


People also ask

How do you remove an entry from a Collection while iterating over a Collection?

An element can be removed from a Collection using the Iterator method remove(). This method removes the current element in the Collection. If the remove() method is not preceded by the next() method, then the exception IllegalStateException is thrown.

How do you delete while iterating?

If you want to delete elements from a list while iterating, use a while-loop so you can alter the current index and end index after each deletion.

Can we modify Collection while iterating?

It is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances.

How do I remove an Object from a collection in Java?

remove() method is used to remove elements from a collection. It removes the element at the specified position in this list. Shifts any subsequent elements to the left by subtracts one from their indices.


1 Answers

Normally when you remove an element from a collection while looping over the collection, you'll get a Concurrent Modification Exception. This is partially why the Iterator interface has a remove() method. Using an iterator is the only safe way to modify a collection of elements while traversing them.

The code would go something like this:

Set<SomeClass> set = new HashSet<SomeClass>(); fillSet(set); Iterator<SomeClass> setIterator = set.iterator(); while (setIterator.hasNext()) {     SomeClass currentElement = setIterator.next();     if (setOfElementsToRemove(currentElement).size() > 0) {         setIterator.remove();     } } 

This way you'll safely remove all elements that generate a removal set from your setOfElementsToRemove().

EDIT

Based on a comment to another answer, this may be more what you want:

Set<SomeClass> set = new HashSet<SomeClass>(); Set<SomeClass> removalSet = new HashSet<SomeClass>(); fillSet(set);  for (SomeClass currentElement : set) {     removalSet.addAll(setOfElementsToRemove(currentElement); }  set.removeAll(removalSet); 
like image 143
Peter Avatar answered Sep 22 '22 09:09

Peter