Java, multiple iterators on a set, removing proper subsets and ConcurrentModificationException

雨燕双飞 提交于 2019-12-01 09:28:05

You can't modify the collection with it2 and continue iterating it with it. Just as the exception says, it's concurrent modification, and it's not supported.

I'm afraid you're stuck with an intermediate collection.

Edit

Actually, your code doesn't seem you make sense: are you sure it's a collection of Integer and not of Set<Integer>? In your code p and q are Integers, so "if q is a subset of p" doesn't seem to make too much sense.

One obvious way to make this a little smarter: sort your sets by size first, as you go from largest to smallest, add the ones you want to keep to a new list. You only have to check each set against the keep list, not the whole original collection.

The idea behind the ConcurrentModificationException is to maintain the internal state of the iterators. When you add or delete things from a set of items, it will throw an exception even if nothing appears wrong. This is to save you from coding errors that would end up throwing a NullPointerException in otherwise mundane code. Unless you have very tight space constraints or have an extremely large collection, you should just make a working copy that you can add and delete from without worry.

How about creating another set subsetNeedRemoved containing all subsets you are going to remove? For each subset, if there is a proper superset, add the subset to subsetNeedRemoved. At the end, you can loop over subsetNeedRemoved and remove corresponding subsets in the original set.

I'd write something like this...

PriorityQueue<Set<Integer>> queue = new PriorityQueue<Set<Integer>>(16, 
 new Comparator<Set<Integer>>() {
  public int compare(Set<Integer> a, Set<Integer> b) {
    return b.size() - a.size(); // overflow-safe!
  }
});
queue.addAll(sets); // we'll extract them in order from largest to smallest
List<Set<Integer>> result = new ArrayList<>();
while(!queue.isEmpty()) {
  Set<Integer> largest = queue.poll();
  result.add(largest);
  Iterator<Set<Integer>> rest = queue.iterator();
  while(rest.hasNext()) {
    if(largest.containsAll(rest.next())) {
      rest.remove();
    }
  }
}

Yeah, it consumes some extra memory, but it's idiomatic, straightforward, and possibly faster than another approach.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!