使用Java流删除和收集元素

dim*_*414 15 java java-8 java-stream

假设我有一个Collection,和一个Predicate匹配我想从中移除的元素Collection.但我不只是想丢弃它们,我想将匹配的元素移动到一个新的集合中.我会做一些像这样在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我很好奇是否有流/ Java 8方法可以做到这一点. Collections.removeIf()不幸的是简单地返回一个boolean(甚至没有删除元素的数量?太糟糕了.)我设想这样的东西(虽然当然.removeAndYield(Predicate)不存在):

List<E> removed = data.removeAndYield(predicate).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

注意:这个问题的灵感来自类似的问题 ; 这个问题是关于从集合中删除项目获取流的更一般情况.正如在链接问题中指出的那样,必要的解决方案可能更具可读性,但我很好奇是否甚至可以使用流.

编辑:显然,我们可以将任务分成两个单独的步骤,并假设适当的数据结构,它将是有效的.问题是可以在任意集合(可能没有效率.contains()等)上完成.

Stu*_*rks 20

如果你不介意的话,让我稍微弯曲你的要求.:-)

期望结果的一个特征是匹配元素应该在一个集合中结束,并且非匹配元素应该最终在不同的集合中.在Java-8之前的变异世界中,考虑获取非匹配元素集合的最简单方法是从原始集合中删除匹配元素.

但是删除 - 修改原始列表 - 需求的内在部分?

如果不是,则可以通过简单的分区操作来实现结果:

Map<Boolean, List<E>> map = data.stream().collect(partitioningBy(predicate));
Run Code Online (Sandbox Code Playgroud)

结果映射本质上是两个列表,其中包含匹配(key = true)和非匹配(key = false)元素.

优点是该技术可以在一次通过中并且在必要时并行完成.当然,与从原始匹配中删除匹配相比,这会创建一个重复的非匹配元素列表,但这是为不变性付出的代价.权衡可能是值得的.

  • 好建议.可变集合通常比它们的价值更麻烦,所以很高兴看到使用不可变集合有一种简单的方法. (4认同)

Mis*_*sha 13

我会保持简单:

Set<E> removed = set.stream()
    .filter(predicate)
    .collect(Collectors.toSet());

set.removeAll(removed);
Run Code Online (Sandbox Code Playgroud)