Удаление объектов от набора в Java при итерации по нему

Основное отличие состоит в том, что C # (если говорить о сети) выполняется на сервере и JS на клиенте . Вы не можете выполнить C # на клиенте. Вот и все. Оба языка завершены по Тьюрингу, так что не волнуйтесь:)

30
задан nash 10 November 2009 в 06:49
поделиться

9 ответов

Обычно, когда вы удаляете элемент из коллекции во время цикла по коллекции, вы получить исключение одновременной модификации . Отчасти поэтому интерфейс Iterator имеет метод remove (). Использование итератора - единственный безопасный способ изменить коллекцию элементов при их обходе.

Код будет выглядеть примерно так:

Set<SomeClass> set = new HashSet<SomeClass>();
fillSet(set);
Iterator<SomeClass> setIterator = set.iterator();
while (setIterator.hasNext()) {
    SomeClass currentElement = setIterator.next();
    if (setOfElementsToRemove(currentElement).size() > 0) {
        setIterator.remove();
    }
}

Таким образом вы безопасно удалите все элементы, которые генерируют набор для удаления из вашего setOfElementsToRemove ( ).

РЕДАКТИРОВАТЬ

На основании комментария к другому ответу, это может быть больше того, что вам нужно:

Set<SomeClass> set = new HashSet<SomeClass>();
Set<SomeClass> removalSet = new HashSet<SomeClass>();
fillSet(set);

for (SomeClass currentElement : set) {
    removalSet.addAll(setOfElementsToRemove(currentElement);
}

set.removeAll(removalSet);
40
ответ дан 27 November 2019 в 23:35
поделиться

Вместо того, чтобы перебирать все элементы в наборе, чтобы удалить те, которые вам нужны, вы можете использовать Коллекции Google (хотя вы не можете сделать это самостоятельно) и применить Предикат для маски тех, которые вам не нужны.

package com.stackoverflow.q1675037;

import java.util.HashSet;
import java.util.Set;

import org.junit.Assert;
import org.junit.Test;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;


public class SetTest
{
public void testFilter(final Set<String> original, final Set<String> toRemove, final Set<String> expected)
{

    Iterable<String> mask = Iterables.filter(original, new Predicate<String>()
    {
        @Override
        public boolean apply(String next) {
        return !toRemove.contains(next);
        }
    });

    HashSet<String> filtered = Sets.newHashSet(mask);

    Assert.assertEquals(original.size() - toRemove.size(), filtered.size());
    Assert.assertEquals(expected, filtered);        
}


@Test
public void testFilterNone()
{
    Set<String> original = new HashSet<String>(){
        {
            this.add("foo");
            this.add("bar");
            this.add("foobar");
        }
    };

    Set<String> toRemove = new HashSet();

    Set<String> expected = new HashSet<String>(){
        {
            this.add("foo");                
            this.add("bar");
            this.add("foobar");
        }
    };

    this.testFilter(original, toRemove, expected);
}

@Test
public void testFilterAll()
{
    Set<String> original = new HashSet<String>(){
        {
            this.add("foo");
            this.add("bar");
            this.add("foobar");
        }
    };

    Set<String> toRemove = new HashSet<String>(){
        {
            this.add("foo");
            this.add("bar");
            this.add("foobar");
        }
    };

    HashSet<String> expected = new HashSet<String>();
    this.testFilter(original, toRemove, expected);
}    

@Test
public void testFilterOne()
{
    Set<String> original = new HashSet<String>(){
        {
            this.add("foo");
            this.add("bar");
            this.add("foobar");
        }
    };

    Set<String> toRemove = new HashSet<String>(){
        {
            this.add("foo");
        }
    };

    Set<String> expected = new HashSet<String>(){
        {
            this.add("bar");
            this.add("foobar");
        }
    };

    this.testFilter(original, toRemove, expected);
}    


@Test
public void testFilterSome()
{
    Set<String> original = new HashSet<String>(){
        {
            this.add("foo");
            this.add("bar");
            this.add("foobar");
        }
    };

   Set<String> toRemove = new HashSet<String>(){
        {
            this.add("bar");
            this.add("foobar");
        }
    };

    Set<String> expected = new HashSet<String>(){
        {
            this.add("foo");
        }
    };

    this.testFilter(original, toRemove, expected);
}    
}
9
ответ дан 27 November 2019 в 23:35
поделиться

Любое решение, которое включает удаление из набора, который вы повторяете, во время итерации, но не через итератор, абсолютно не будет работать. Кроме, возможно, одного: вы можете использовать Collections.newSetFromMap (new ConcurrentHashMap ( параметры размера )) . Загвоздка в том, что теперь ваш итератор только слабо согласован , что означает, что каждый раз, когда вы удаляете элемент, с которым еще не сталкивались, не определено, появится ли этот элемент позже в вашей итерации или нет. Если это не проблема, это может сработать для вас.

Еще вы можете создать набор toRemove по ходу работы, а затем set.removeAll (itemsToRemove); ] только в конце. Или скопируйте набор перед тем, как начать,

6
ответ дан 27 November 2019 в 23:35
поделиться

Вы можете попробовать java.util.concurrent.CopyOnWriteArraySet , который дает вам итератор, который представляет собой снимок набора во время создания итератора. Любые изменения, которые вы вносите в набор (например, вызывая removeAll () ), не будут видны в итераторе, но будут видны, если вы посмотрите на сам набор (и removeAll () ] не бросит).

6
ответ дан 27 November 2019 в 23:35
поделиться

На этот вопрос есть простой ответ - используйте метод Iterator.remove ().

2
ответ дан 27 November 2019 в 23:35
поделиться

If you have enough memory for one copy of the set, I'll assume you also have enough memory for two copies. The Kafka-esque rules you cite don't seem to forbid that :)

My suggestion, then:

fillSet(set);
fillSet(copy);
for (Object item : copy) {
   if (set.contains(item)) { // ignore if not
     set.removeAll(setOfStuffToRemove())
   }
}

so copy stays intact and just provides the stuff to loop on, while set suffers deletions. Stuff that was removed from set in the meantime will be ignored.

2
ответ дан 27 November 2019 в 23:35
поделиться

Почему бы вам не использовать метод удаления итератора для объектов, которые вы хотите удалить ?

Итераторы были введены в основном потому, что счетчики не могли обрабатывать удаление во время перечисления.

1
ответ дан 27 November 2019 в 23:35
поделиться

Вы должны вызвать метод Iterator.remove .

Также обратите внимание, что в большинстве коллекций java.util remove ] вызовет исключение, если содержимое коллекции изменилось. Поэтому, если код является многопоточным, будьте осторожны или используйте параллельные коллекции.

0
ответ дан 27 November 2019 в 23:35
поделиться

Можно реализовать Набор , который позволяет удалять его элементы во время итерации по нему.

Я думаю, что стандартные реализации (HashSet, TreeSet и т. Д.) запретить это, потому что это означает, что они могут использовать более эффективные алгоритмы, но это несложно.

Вот неполный пример с использованием Google Collections:

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.google.common.base.Predicates;
import com.google.common.collect.ForwardingSet;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;

public class ConcurrentlyModifiableSet<E>
extends ForwardingSet<E> {
 /** Create a new, empty set */
 public ConcurrentlyModifiableSet() {
  Map<E, Boolean> map = new ConcurrentHashMap<E, Boolean>();
  delegate = Sets.newSetFromMap(map);
 }

 @Override
 public Iterator<E> iterator() {
  return Iterators.filter(delegate.iterator(), Predicates.in(delegate));
 }

 @Override
 protected Set<E> delegate() {
  return this.delegate;
 }

 private Set<E> delegate;
}

Примечание: итератор не поддерживает remove () операция (но пример в вопросе не требует этого.)

0
ответ дан 27 November 2019 в 23:35
поделиться
Другие вопросы по тегам:

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