Removing items from a collection in java while iterating over it

后端 未结 10 1738

I want to be able to remove multiple elements from a set while I am iterating over it. Initially I hoped that iterators were smart enough for the naive solution below to wor

相关标签:
10条回答
  • 2020-11-28 09:15

    Why don't you use the iterator's remove method on the objects you want to remove?

    Iterators were introduced mainly because enumerators couldn't handle deleting while enumerating.

    0 讨论(0)
  • 2020-11-28 09:23

    There's a simple answer to this - use the Iterator.remove() method.

    0 讨论(0)
  • 2020-11-28 09:24

    Instead of iterating through all the elements in the Set to remove the ones you want, you can actually use Google Collections (not something you can't do it on your own though) and apply a Predicate to mask the ones you don't need.

    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);
    }    
    }
    
    0 讨论(0)
  • 2020-11-28 09:25

    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.

    0 讨论(0)
提交回复
热议问题