1

What I'm trying to achieve is the following: While iterating over both the keys and values of a Multimap<K,V>, I want to remove and put back elements from this list. Any approach I've tried ends up in a ConcurrentModificationException. This remove-and-put-back-approach is required to implement a backtrack search (see here: Implementing a backtrack search with heuristic? )

This may look like:

Multimap<K,V> multimap = HashMultimap.create();
Iterator keyIterator = multimap.keySet().iterator();

while(keyIterator.hasNext()) {
  K key = keyIterator.next();
  Collection values = multimap.get(key);

  Iterator valueIterator = values.iterator();
  while(valueIterator.hasNext()) {
    V myValue = valueIterator.next();
    if(special) {
      valueIterator.remove();
      keyIterator.remove();
      // recursion
      // put back Collection with key but without myValue <-- HOW?
    }
  }
}
Community
  • 1
  • 1
user26372
  • 279
  • 1
  • 2
  • 14
  • 1
    Not sure I understand, if you simply want to remove a myValue from the collection, why don't you do that: `V myValue = valueIterator.next(); if (special) valueIterator.remove();`? – assylias May 19 '13 at 11:32
  • Removing is not the issue. Putting it back while iterating it is. The pseudocode already removes the value from the collection and removes the rest of the collection as well. After the recursion I would now like to put the collection back again into the multimap (but without the previously removed value). – user26372 May 19 '13 at 12:27
  • It's not clear why you need to temporarily remove the rest of the collection from the `Multimap` at all, but if you really need to, why don't you put it into a second `Multimap`, and either use that new `Multimap` directly afterwards or add it back to the original one. – Frank Pavageau May 20 '13 at 20:51
  • It would be nice to omit the copy operation for a second MultiMap. The recursion works on the same MultiMap (on it's reduced 'state'). So there should be no need to actually copy the MultiMap for the recursion if we can easily remove and add back elements. – user26372 May 22 '13 at 21:25

1 Answers1

3

One solution is to iterate over a copy of keySet, e.g.

K[] array = multiMap.keySet().toArray(new K[0]);
for(int i = 0; i < array.length; i++) {
    K key = array[i];
    ...
}

Changes to the underlying map won't be reflected in array, so you won't get a ConcurrentModificationException if you use an Iterator on it, and you won't get any weird behavior if you iterate over it with a for loop.

Another option is to copy-paste the source code for MultiMap into a new collection MyMultiMap, except that you'd replace the top-level HashMap with a ConcurrentHashMap - the latter's iterators won't throw ConcurrentModificationExceptions.

Another option is to coalesce the two loops into one loop, and iterate directly over the map's entries - this way you'll only have one iterator, so you won't have the problem of one iterator causing ConcurrentModificationExceptions in a second iterator.

Zim-Zam O'Pootertoot
  • 17,440
  • 4
  • 38
  • 67