假设我有一个 Collection
和一个 Predicate
匹配我想从 Collection
中删除的元素。但我不只是想丢弃它们,我想将匹配的元素移动到一个新的集合中。我会做类似 this 的事情在 Java 7 中:
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()
等)。
最佳答案
如果您不介意,让我稍微改变一下您的要求。 :-)
期望结果的一个特征是匹配的元素应该在一个集合中结束,而不匹配的元素应该在不同的集合中结束。在 Java-8 之前的可变世界中,考虑获取不匹配元素集合的最简单方法是从原始集合中删除匹配元素。
但是删除——原始列表的修改——是要求的固有部分吗?
如果不是,则可以通过简单的分区操作获得结果:
Map<Boolean, List<E>> map = data.stream().collect(partitioningBy(predicate));
结果映射本质上是两个列表,其中包含匹配(key = true)和非匹配(key = false)元素。
优点是这项技术可以一次性完成,必要时可以并行完成。当然,与从原始列表中删除匹配项相比,这会创建一个不匹配元素的重复列表,但这是为不可变性付出的代价。权衡可能是值得的。
关于java - 使用 Java 流移除和收集元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30042222/