Java,集合上的多个迭代器,删除适当的子集和 ConcurrentModificationException

发布于 2025-01-05 04:13:04 字数 1143 浏览 1 评论 0原文

我有一个集合 A = {(1,2), (1,2,3), (2,3,4), (3,4), (1)}

我想把它变成 A={(1 ,2,3),(2,3,4)},从该集合中删除真子集。

我使用 HashSet 来实现集合,使用 2 个迭代器来运行集合并使用 containsAll(c) 检查所有对的正确子集条件,并使用 remove() 方法删除正确子集。

代码看起来像这样:

HashSet<Integer> hs....
Set<Integer> c=hs.values();
Iterator<Integer> it= c.iterator();
while(it.hasNext())
{
    p=it.next();
    Iterator<Integer> it2= c.iterator();
    while(it2.hasNext())
    {
        q=it2.next();
        if q is a subset of p
            it2.remove();
        else if p is a subset of q
        {
            it.remove();
            break;
        }
    }
}

当我第一次从内部 while 循环中出来并执行 a 操作时,我得到一个 ConcurrentModificationException 。

p=it.next();

异常是在迭代集合时修改集合时。但这就是 .remove() 的用途。

我在仅使用 1 个迭代器时使用了remove(),并且没有遇到任何问题。

如果异常是因为我在迭代“c”或“hs”时从“c”或“hs”中删除一个元素,那么当它遇到下一个 it 2 .next() 命令时,应该抛出异常,但当时我没有看到。当它遇到 it.next() 命令时我会看到它。

我使用了调试器,并且在删除元素后,集合和迭代器处于完美的顺序。它们包含并指向正确的更新集和元素。 it.next() 包含下一个要分析的元素,它不是已删除的元素。

关于如何在提交更新之前不复制哈希集本身并将其用作中间体的情况下如何做我想做的事情,有什么想法吗?

谢谢

I have a set A = {(1,2), (1,2,3), (2,3,4), (3,4), (1)}

I want to turn it into A={(1,2,3), (2,3,4)}, remove proper subsets from this set.

I'm using a HashSet to implement the set, 2 iterator to run through the set and check all pairs for proper subset condition using containsAll(c), and the remove() method to remove proper subsets.

the code looks something like this:

HashSet<Integer> hs....
Set<Integer> c=hs.values();
Iterator<Integer> it= c.iterator();
while(it.hasNext())
{
    p=it.next();
    Iterator<Integer> it2= c.iterator();
    while(it2.hasNext())
    {
        q=it2.next();
        if q is a subset of p
            it2.remove();
        else if p is a subset of q
        {
            it.remove();
            break;
        }
    }
}

I get a ConcurrentModificationException the 1st time i come out of the inner while loop and do a

p=it.next();

The exception is for when modifying the Collection while iterating over it. But that's what .remove() is for.

I have used remove() when using just 1 iterator and encountered no problems there.

If the exception is because I'm removing an element from 'c' or 'hs' while iterating over it, then the exception should be thrown when it encounter the very next it 2 .next() command, but I don't see it then. I see it when it encounters the it.next() command.

I used the debugger, and the collections and iterators are in perfect order after the element has been removed. They contain and point to the proper updated set and element. it.next() contains the next element to be analyzed, it's not a deleted element.

Any ideas over how i can do what i'm trying to do without making a copy of the hashset itself and using it as an intermediate before I commit updates?

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

假面具 2025-01-12 04:13:04

continue

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.

心凉怎暖 2025-01-12 04:13:04

ConcurrentModificationException 背后的想法是维护迭代器的内部状态。当您从一组项目中添加或删除内容时,即使没有出现任何错误,它也会引发异常。这是为了避免编码错误,这些错误最终会在普通代码中引发 NullPointerException 。除非您有非常紧张的空间限制或拥有非常大的集合,否则您应该只制作一个工作副本,您可以放心地添加和删除它。

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.

梦亿 2025-01-12 04:13:04

如何创建另一个包含要删除的所有子集的集合subsetNeedRemoved?对于每个子集,如果存在适当的超集,则将该子集添加到subsetNeedRemoved。最后,您可以循环subsetNeedRemoved并删除原始集中相应的子集。

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.

爱,才寂寞 2025-01-12 04:13:04

我会写这样的东西......

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();
    }
  }
}

是的,它消耗一些额外的内存,但它是惯用的,简单的,并且可能比其他方法更快。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文