Java, несколько итераторов в наборе, удаление правильных подмножеств и исключение ConcurrentModificationException - PullRequest
3 голосов
/ 14 февраля 2012

У меня есть набор 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;
        }
    }
}

Я получаю исключение ConcurrentModificationException в первый раз, когда выхожу из внутреннего цикла while и выполняю

p=it.next();

Исключение составляют изменения коллекции при ее итерации по ней. Но для этого .remove ().

Я использовал метод remove (), когда использовал только один итератор, и проблем там не было.

Если исключение вызвано тем, что я удаляю элемент из 'c' или 'hs' во время итерации по нему, то исключение должно быть выдано, когда оно встречается с ближайшим к нему 2 .next ( ), но я этого не вижу. Я вижу это, когда встречается с командой it.next ().

Я использовал отладчик, и коллекции и итераторы находятся в идеальном порядке после удаления элемента. Они содержат и указывают на соответствующий обновленный набор и элемент. it.next () содержит следующий элемент для анализа, это не удаленный элемент.

Есть какие-нибудь идеи относительно того, как я могу делать то, что я пытаюсь сделать, не делая копию самого хэш-набора и используя его в качестве промежуточного звена до того, как я фиксирую обновления?

Спасибо

Ответы [ 4 ]

1 голос
/ 14 февраля 2012

Нельзя изменить коллекцию с помощью it2 и продолжить итерацию с помощью it.Как говорится в исключении, это одновременная модификация, и она не поддерживается.

Боюсь, вы застряли с промежуточной коллекцией.

Редактировать

На самом деле, вашкажется, что код не имеет смысла: вы уверены, что это коллекция Integer, а не Set<Integer>?В вашем коде p и q являются Integer s, поэтому «если q является подмножеством p», кажется, не имеет особого смысла.

Один очевидный способ сделать это немногоумнее: сначала сортируйте наборы по размеру, переходя от самого большого к наименьшему, добавляйте те, которые хотите сохранить, в новый список.Вам нужно только проверить каждый набор по списку keep, а не по всей оригинальной коллекции.

0 голосов
/ 14 февраля 2012

Я бы написал что-то вроде этого ...

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

Да, он потребляет немного дополнительной памяти, но он идиоматичен, прямолинеен и, возможно, быстрее, чем другой подход.

0 голосов
/ 14 февраля 2012

Как насчет создания другого набора subsetNeedRemoved, содержащего все подмножества, которые вы собираетесь удалить?Для каждого подмножества, если существует правильный надмножество, добавьте подмножество в subsetNeedRemoved.В конце вы можете перебрать subsetNeedRemoved и удалить соответствующие подмножества из исходного набора.

0 голосов
/ 14 февраля 2012

Идея ConcurrentModificationException состоит в том, чтобы поддерживать внутреннее состояние итераторов. Когда вы добавляете или удаляете вещи из набора предметов, выдается исключение, даже если ничего не выглядит неправильно. Это избавит вас от ошибок кодирования, которые в конечном итоге приведут к выдаче NullPointerException в противном случае обыденного кода. Если у вас нет очень жестких ограничений по пространству или у вас очень большая коллекция, вам просто нужно создать рабочую копию, которую вы можете добавлять и удалять, не беспокоясь.

...