假设我有一个Collection
和一个Predicate
,它与我想要从Collection
删除的元素相匹配。但我不想丢弃它们,我想将匹配的元素移动到新的集合中。我在Java 7中做this之类的事情:
List<E> removed = new LinkedList<>();
for (Iterator<E> i = data.iterator(); i.hasNext();) {
E e = i.next();
if (predicate.test(e)) {
removed.add(e);
i.remove();
}
}
我很好奇是否有一个流/ Java 8方法可以做到这一点。不幸的是,Collections.removeIf()
只返回一个boolean
(甚至没有删除元素数量的数量?太糟糕了。)我设想这样的事情(虽然当然.removeAndYield(Predicate)
不存在):
List<E> removed = data.removeAndYield(predicate).collect(Collectors.toList());
注意:这个问题的灵感来自a similar question;这个问题是关于从集合中删除项目获取流的更一般情况。正如在链接问题中所指出的那样,必要的解决方案可能更具可读性,但我很好奇是否可以使用流。
编辑:显然,我们可以将任务分成两个单独的步骤,并假设适当的数据结构将有效。问题是可以在任意集合上完成(可能没有高效的.contains()
等)。
答案 0 :(得分:20)
如果你不介意,让我稍微弯曲你的要求。 : - )
期望结果的一个特征是匹配元素应该在一个集合中结束,并且非匹配元素应该最终在不同的集合中。在Java-8之前的变异世界中,考虑获取非匹配元素集合的最简单方法是从原始集合中删除匹配元素。
但是删除 - 原始列表的修改 - 要求的内在部分?
如果不是,那么可以通过简单的分区操作来实现结果:
extrafont
结果映射本质上是两个列表,其中包含匹配(key = true)和非匹配(key = false)元素。
优点是该技术可以在一次通过中并且在必要时并行完成。当然,与从原始匹配中删除匹配相比,这会创建一个重复的非匹配元素列表,但这是为不变性付出的代价。权衡可能是值得的。
答案 1 :(得分:13)
我保持简单:
Set<E> removed = set.stream()
.filter(predicate)
.collect(Collectors.toSet());
set.removeAll(removed);
答案 2 :(得分:4)
如果你想要一种功能性的方法,你可以编写自己的方法。
movieInfo.js:56
return fn(err, p)
^
TypeError: undefined is not a function
这可用于删除static <E> Set<E> removeIf(Collection<? extends E> collection, Predicate<? super E> predicate) {
Set<E> removed = new HashSet<>();
for (Iterator<? extends E> i = collection.iterator(); i.hasNext();) {
E e = i.next();
if (predicate.test(e)) {
removed.add(e);
i.remove();
}
}
return removed;
}
中的所有奇数。
List
答案 3 :(得分:0)
只需为自己写一个可重复使用的函数:
/**
* Removes all matching element from iterator
*
* @param it
* @param predicate
*/
public static <E> void removeMatching(final Iterator<E> it, final Predicate<E> predicate) {
while (it.hasNext()) {
final E e = it.next();
if (predicate.test(e)) {
it.remove();
}
}
}
我还没有找到Streams的预先存在的解决方案。使用iterator.remove()比临时集需要更少的内存。