0

I'd like to compare elements within a set, in order to merge elements too similar. In order to gain some time, I would like to erase similarities during the iteration. Here how I try to proceed:

Iterator<Personne> i1 = personnes.iterator();
while (i1.hasNext()) {
     Personne personneObservee = i1.next();
     Set<Personne> tmp = new HashSet<Personne>();
     tmp.addAll(personnes);
     Iterator<Personne> i2 = tmp.iterator();
     while (i2.hasNext()) {
        Personne autrePersonne = i2.next();
        if (personneObservee.isSimilarTo(autrePersonne)) {
            personnes.remove(autrePersonne);
        }
    }
    result.add(personneObservee.toString());
}

As you can guess from my presence here, it doesn't work, giving me this nice stacktrace :

java.util.ConcurrentModificationException
        at java.util.HashMap$HashIterator.nextEntry(HashMap.java:926)
        at java.util.HashMap$KeyIterator.next(HashMap.java:960)
        at NameDetectorWithBenefits.mergeSamePersons(NameDetectorWithBenefits.java:41)
        at App.main(App.java:71)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:297)
        at java.lang.Thread.run(Thread.java:744)

At first, I thought i1 and i2 were iterating over the same set and that I would find an answer here. As a consequence, I create a temporary set each time. However, it didn't resolve the problem.

Any ideas where the trouble might come from ?

Community
  • 1
  • 1
merours
  • 4,076
  • 7
  • 37
  • 69

4 Answers4

1

Use Iterator#remove() rather than Set#remove(Object).

So replace the following line

personnes.remove(autrePersonne);

with

i2.remove();

See here for more details.

Community
  • 1
  • 1
asaini007
  • 858
  • 5
  • 19
  • Although this is correct, how do you apply this to his particular example? – Josh M Feb 25 '14 at 17:55
  • Is there a difference between `It#remove` and `It.remove` or is this just convention ? – merours Feb 25 '14 at 18:07
  • @fxm `Iterator#remove()` simply refers to the `remove()` method of the `Iterator` class. In your code you'd call that method on your `Iterator` object (i.e. `12.remove()`) – asaini007 Feb 25 '14 at 18:14
1

While iterating through a set use the iterator to delete elements from the set rather than using set.remove()

// wrong way
personnes.remove(autrePersonne); 

//correct way
it.remove(); 
Kakarot
  • 4,252
  • 2
  • 16
  • 18
0

You can't update the SET while another thread is iterating it due to which ConcurrentModificationException exception arise.

You are iterating the SET

Iterator<Personne> i1 = personnes.iterator(); and use personnes.remove(autrePersonne); to remove the element.

use Iterator remove method to remove the element

Kick
  • 4,823
  • 3
  • 22
  • 29
0

Do it in two steps:

  1. isolate what need removal
  2. remove

.

final Set<Personne> toRemove = new HashSet<>();
for (final Personne personne: personnes) {
    for (final Personne autrePersonne: personnes) {
        if (person.isSimilarTo(autrePersonne)) {
            toRemove.add(autrePersonne);
        }
    }
}
personnes.removeAll(toRemove);

Also, you need to take care of the case where autrePersonne equals personne

  • While it probably works, it's more expensive in terms of complexity than what I'm trying to achieve. – merours Feb 25 '14 at 18:18