在java中迭代集合时从集合中移除项
我希望能够在迭代时从集合中删除多个元素。起初,我希望迭代器足够聪明,可以让下面的简单解决方案工作在java中迭代集合时从集合中移除项,java,collections,set,Java,Collections,Set,我希望能够在迭代时从集合中删除多个元素。起初,我希望迭代器足够聪明,可以让下面的简单解决方案工作 Set<SomeClass> set = new HashSet<SomeClass>(); fillSet(set); Iterator<SomeClass> it = set.iterator(); while (it.hasNext()) { set.removeAll(setOfElementsToRemove(it.next())); } se
Set<SomeClass> set = new HashSet<SomeClass>();
fillSet(set);
Iterator<SomeClass> it = set.iterator();
while (it.hasNext()) {
set.removeAll(setOfElementsToRemove(it.next()));
}
setofelementstoremoveincludingpassedvalue()
将生成一组要删除的元素,其中包括传递给它的值。我们需要删除传递的值,以便set
将为空
我的问题是,是否有人有更好的方法来执行此操作,或者是否有支持此类删除的收集操作
另外,我想我会发布我的解决方案,因为似乎有必要,我想贡献优秀的资源,即堆栈溢出。对此有一个简单的答案-使用Iterator.remove()方法。为什么不在要删除的对象上使用
引入迭代器的主要原因是枚举器在枚举时无法处理删除操作。您应该调用
Iterator.remove
方法
还要注意的是,在大多数
java.util
集合中,如果集合的内容发生更改,remove
方法将生成异常。因此,如果代码是多线程的,请格外小心,或者使用并发集合。通常,当您在集合上循环时从集合中删除元素时,您会得到一个错误。这就是接口具有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();
}
}
Set Set=newhashset();
填充集(套);
迭代器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);
Set Set=newhashset();
Set removalSet=new HashSet();
填充集(套);
对于(SomeClass currentElement:set){
removalSet.addAll(setOfElementsToRemove(currentElement));
}
集合。移除所有(移除集合);
任何涉及在迭代时从正在迭代的集合中删除而不是通过迭代器的解决方案都绝对无效。可能的情况除外:您可以使用Collections.newSetFromMap(新的ConcurrentHashMap(大小参数))
。问题是,现在您的迭代器只是弱一致性,这意味着每次删除尚未遇到的元素时,该元素是否会在以后的迭代中出现都是未定义的。如果这不是问题,这可能对您有效
您可以做的另一件事是在运行时构建一个toRemove
集,然后set.removeAll(itemsToRemove);
仅在末尾。或者,在开始之前复制该集,这样您可以在从另一个副本移除的同时迭代一个副本
编辑:哎呀,我看到Peter Nix已经提出了删除的想法(尽管是不必要的手动删除)。你可以使用Google Collections,而不是遍历集合中的所有元素来删除你想要的元素并应用谓词来屏蔽不需要的谓词
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);
}
}
package com.stackoverflow.q1675037;
导入java.util.HashSet;
导入java.util.Set;
导入org.junit.Assert;
导入org.junit.Test;
导入com.google.common.base.Predicate;
导入com.google.common.collect.Iterables;
导入com.google.common.collect.set;
公共类设置测试
{
公共无效测试过滤器(最终原始设置、最终删除设置、预期最终设置)
{
Iterable mask=Iterables.filter(原始,新谓词()
{
@凌驾
公共布尔应用(字符串下一步){
return!toRemove.contains(下一步);
}
});
HashSet filtered=Sets.newHashSet(掩码);
Assert.assertEquals(original.size()-toRemove.size(),filtered.size());
Assert.assertEquals(预期、筛选);
}
@试验
公共void testFilterNone()
{
Set original=new HashSet(){
{
本条。添加(“foo”);
本条。添加(“酒吧”);
本条。添加(“foobar”);
}
};
Set toRemove=newhashset();
Set expected=新的HashSet(){
{
本条。添加(“foo”);
本条。添加(“酒吧”);
本条。添加(“foobar”);
}
};
此.testFilter(原始、删除、预期);
}
@试验
public void testFilterAll()
{
Set original=new HashSet(){
{
本条。添加(“foo”);
本条。添加(“酒吧”);
本条。添加(“foobar”);
}
};
Set toRemove=newhashset(){
{
本条。添加(“foo”);
本条。添加(“酒吧”);
本条。添加(“foobar”);
}
};
HashSet预期值=新的HashSet();
此.testFilter(原始、删除、预期);
}
@试验
public void testFilterOne()
{
Set original=new HashSet(){
{
本条。添加(“foo”);
本条。添加(“酒吧”);
本条。添加(“foobar”);
}
};
Set toRemove=newhashset(){
{
本条。添加(“foo”);
}
};
Set expected=新的HashSet(){
{
本条。添加(“酒吧”);
本条。添加(“foobar”);
}
};
此.testFilter(原始、删除、预期);
}
@试验
公共void testFilterSome()
{
Set original=new HashSet(){
{
本条。添加(“foo”);
本条。添加(“酒吧”);
本条。添加(“foobar”);
}
};
Set toRemove=newhashset(){
{
本条。添加(“酒吧”);
本条。添加(“foobar”);
}
};
Set expected=新的HashSet(){
{
本条。添加(“foo”);
}
};
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);
}
}
fillSet(set);
fillSet(copy);
for (Object item : copy) {
if (set.contains(item)) { // ignore if not
set.removeAll(setOfStuffToRemove())
}
}
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;
}