Удалите Элементы из HashSet, в то время как Итерация [копирует]

Соответствующий раздел спецификации C# 3.0 7.13, условный оператор:

вторые и третьи операнды?: управление оператором тип условного выражения. Позвольте X и Y быть типами вторых и третьих операндов. Затем

, Если X и Y являются тем же типом, то это - тип условного выражения Иначе, если неявное преобразование (В§6.1) существует от X до Y, но не от Y до X, то Y является типом условного выражения. Иначе, если неявное преобразование (В§6.1) существует от Y до X, но не от X до Y, то X тип условного выражения. Иначе никакой тип выражения не может быть определен, и ошибка времени компиляции происходит.

114
задан 10 July 2009 в 15:52
поделиться

5 ответов

Вы можете вручную перебирать элементы набора:

Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
    Integer element = iterator.next();
    if (element % 2 == 0) {
        iterator.remove();
    }
}

Вы часто будете видеть этот шаблон, используя цикл for , а не while loop:

for (Iterator<Integer> i = set.iterator(); i.hasNext();) {
    Integer element = i.next();
    if (element % 2 == 0) {
        i.remove();
    }
}

Как уже отмечалось, использование цикла for предпочтительнее, потому что он сохраняет переменную итератора ( i в данном случае) ограниченной областью меньшего размера.

179
ответ дан 24 November 2019 в 02:33
поделиться

Причина, по которой вы получаете исключение ConcurrentModificationException , заключается в том, что запись удаляется с помощью Set.remove () в отличие от Iterator.remove ( ) . Если запись удалена с помощью Set.remove () во время итерации, вы получите исключение ConcurrentModificationException. С другой стороны, удаление записей с помощью Iterator.remove () в этом случае поддерживается итерация.

Новый цикл for хорош, но, к сожалению, в этом случае он не работает, потому что вы не может использовать ссылку на итератор.

Если вам нужно удалить запись во время итерации, вам нужно использовать длинную форму, которая напрямую использует итератор.

for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
    Integer element = it.next();
    if (element % 2 == 0) {
        it.remove();
    }
}
19
ответ дан 24 November 2019 в 02:33
поделиться

Должен ли он быть во время итерации? Если все, что вы делаете, это фильтруете или выбираете, я бы предложил использовать Apache Commons CollectionUtils . Там есть несколько мощных инструментов, и это делает ваш код «круче».

Здесь ' s реализация, которая должна предоставить то, что вам нужно:

Set<Integer> myIntegerSet = new HashSet<Integer>();
// Integers loaded here
CollectionUtils.filter( myIntegerSet, new Predicate() {
                              public boolean evaluate(Object input) {
                                  return (((Integer) input) % 2 == 0);
                              }});

Если вы обнаружите, что часто используете один и тот же тип предиката, вы можете вытащить его в статическую переменную для повторного использования ... назовите это как-то вроде EVEN_NUMBER_PREDICATE . Некоторые могут увидеть этот код и объявить его «трудным для чтения», но он выглядит чище, когда вы вытаскиваете предикат в статический. Тогда легко увидеть, что мы делаем CollectionUtils.filter (...) , и он кажется более читаемым (для меня), чем куча циклов на всем протяжении создания.

но он выглядит чище, если вытащить Predicate в статический. Тогда легко увидеть, что мы делаем CollectionUtils.filter (...) , и он кажется более читаемым (для меня), чем куча циклов на всем протяжении создания.

но он выглядит чище, если вытащить Predicate в статический. Тогда легко увидеть, что мы делаем CollectionUtils.filter (...) , и он кажется более читаемым (для меня), чем куча циклов на всем протяжении создания.

4
ответ дан 24 November 2019 в 02:33
поделиться

вы также можете реорганизовать свое решение, удалив первый цикл:

Set<Integer> set = new HashSet<Integer>();
Collection<Integer> removeCandidates = new LinkedList<Integer>(set);

for(Integer element : set)
   if(element % 2 == 0)
       removeCandidates.add(element);

set.removeAll(removeCandidates);
10
ответ дан 24 November 2019 в 02:33
поделиться

Другое возможное решение:

for(Object it : set.toArray()) { /* Create a copy */
    Integer element = (Integer)it;
    if(element % 2 == 0)
        set.remove(element);
}

Или:

Integer[] copy = new Integer[set.size()];
set.toArray(copy);

for(Integer element : copy) {
    if(element % 2 == 0)
        set.remove(element);
}
2
ответ дан 24 November 2019 в 02:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: