2

I have a TreeSet that contains integers. I loop through this set and "consume" the integers one by one. During each loop I need to increase the remaining, uncomsumed integers with 1.

For example, I start with a set with four values: 2, 3, 5, 8. After the first loop where I consume 2 the result should be a set with this content 4, 6 , 9. After the second loop, where 4 is consumed, it should be 7, 10 and so on.

  • I don't need the last value to be increased a step after it has been consumed (but it is ok if it is).
  • It is ok if the consumed values remain in the set, and it doesn't matter if they are at their original or increased value. In other words, after the second loop, it would be ok if the set contained 2, 3, 7, 10 or 2, 4, 7, 10 or just 7, 10. (The set is gonna be discarded after this loop)

This is my code

    for (Integer i : positionSet) {
        TreeSet <Integer> tmpSet = new TreeSet<>(); 
        //use i for something
        //positionSet.remove(i); //I tried with this both on and off, but it made no difference
        for (Integer j : positionSet) {
            tmpSet.add(j + 1);
        }
        positionSet.clear();
        positionSet.addAll(tmpSet);
    }

It crashes on the second round with a java.util.ConcurrentModificationException, which I presume is caused by me modifying the set that is used in the loop-header.

How do I modify the contents of the set while looping over it? I tried copying the set back and forth in a couple of different ways but the code constantly fails with the same error message. I must not modify the set while looping, however modifying the set is the whole purpose of this loop.//

d-b
  • 695
  • 3
  • 14
  • 43
  • What output are you expecting? Are you returning a value from this method? or expecting the results to be in the set? – Arun Gowda Dec 11 '20 at 13:03
  • You should use actual iterators rather than the for-each loops. – NomadMaker Dec 11 '20 at 13:04
  • My endgoal is to insert a random number of dots in a string, according to certain rules: (1) First and last character must not be a dot. (2) Two dots in a row are not allowed. In other words, if I have a six character string `ABCDEF` the max number of dots allowed are 5 (but 0 to 4 are ok). The following results are valid `A.B.C.D.E.F`, `AB.CDEF`, `AB.C.D.EF` while these two are invalid `.AB.C.DEF`, `A.BCD.EF.`. – d-b Dec 11 '20 at 13:04
  • Does this answer your question? [Remove elements from collection while iterating](https://stackoverflow.com/questions/10431981/remove-elements-from-collection-while-iterating) – Glains Dec 11 '20 at 13:07
  • My general algorithm looks like this: (1) length of string -1 is used to get a random value for the number of dots that should be used. (2) loop until a TreeSet has the number of elements decided by (1). These elements decide the position where the dot is inserted and are random. Again, the string length is used to limit the value of the random number. After this I perform this loop. The reason for this +1 is to prevent dots from ending up next to each other. – d-b Dec 11 '20 at 13:10
  • @Glains a `TreeSet` **is** a `Collection`. – Mark Rotteveel Dec 12 '20 at 13:16

1 Answers1

2

You cannot modify a data structure during iteration, except for the allowed provisions. For an iterator this is only Iterator.remove(), but a for-each doesn't have such provision, nor can you affect other elements.

The best you can do is create a while loop that's independent of the data structure:

while (!positionSet.isEmpty()) {
    Integer i = <take one element out of positionSet somehow>;
    //positionSet.remove(i); //remove if the previous line didn't already remove it

    //use i for something
    TreeSet <Integer> tmpSet = new TreeSet<>();
    for (Integer j : positionSet) {
        tmpSet.add(j + 1);
    }
    positionSet.clear();
    positionSet.addAll(tmpSet);
}
Mark Jeronimus
  • 9,278
  • 3
  • 37
  • 50