当前位置: 首页 > 知识库问答 >
问题:

使用Java流删除和收集元素

东典
2023-03-14

假设我有一个集合,还有一个谓词,它匹配我想从集合中删除的元素。但我不只是想丢弃它们,我想将匹配的元素移动到一个新集合中。在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();
    }
}

我很好奇是否有一个流/Java8方法来做这件事。Collections.remove如果()不幸地只是返回一个布尔值(甚至没有删除元素的数量?太糟糕了。)我设想了这样的东西(当然. remveAndYield(谓语)不存在):

List<E> removed = data.removeAndYield(predicate).collect(Collectors.toList());

注:此问题受类似问题启发;这个问题是关于在从集合中移除的项上获取流的更一般的情况。正如链接问题中所指出的,命令式解决方案可能更具可读性,但我很好奇,这在流中是否可行。

编辑:显然,我们可以将任务分成两个独立的步骤,假设适当的数据结构将是有效的。问题是可以在任意集合(可能没有有效的。包含()等)上执行此操作吗?

共有3个答案

海灵均
2023-03-14

如果您想要一种函数式的方法来实现这一点,您可以编写自己的方法。

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;
}

这可用于从列表中删除所有奇数。

Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5, 6));
Set<Integer> removed = removeIf(set, i -> i % 2 != 0);
System.out.println(set);
System.out.println(removed);

鲁辉
2023-03-14

我会保持简单:

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

set.removeAll(removed);
诸葛绍元
2023-03-14

如果您不介意,让我稍微改变一下您的要求。:-)

所需结果的一个特征是匹配的元素应该在一个集合中结束,而非匹配的元素应该在不同的集合中结束。在Java-8之前的变体世界中,考虑获取非匹配元素集合的最简单方法是从原始集合中移除匹配元素。

但是,删除——对原始列表的修改——是需求的固有部分吗?

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

Map<Boolean, List<E>> map = data.stream().collect(partitioningBy(predicate));

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

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

 类似资料:
  • 我想获取地图的值,找到min值,并为地图的每个条目构造一个新的CodesWitMinValue实例。我希望使用Java11个流,我可以在多行中使用多个流(一个用于min值,一个用于转换)来实现这一点。是否可以使用java 11流和收集器在单行中实现?谢谢。

  • 我有一个对象的集合,每个对象都有一个元素的集合,例如: 如何使用Java 8函数式编程来过滤和收集类型等于“a”的集合? 我尝试了以下方法: 但我得到以下错误: 变量'filteredChildren'初始值设定项'parents。stream()。forEach(p- 如何按类型筛选嵌套集合并收集它们?

  • 为了更好地理解新的流API,我试图转换一些旧代码,但我被困在这一个。 我似乎无法为它创建有效的收集器:

  • 问题内容: 我的JsonArray是 现在,我要从此JsonArray中删除ID,ManualScheduled,已选中, 我尝试在JAVA中使用和。但是什么也没发生。我删除阵列项目错了吗? 我正在使用JAVA作为技术。 问题答案: 您所拥有的是一系列对象。因此,您将不得不遍历数组并从 每个 对象中删除必要的数据,例如 我假设您正在使用and ,但是无论使用什么JSON处理库,主体都保持不变。 如

  • 我有一个列表的地图,并希望收集所有的值,然后流在收集的列表上,所以给出:- 下面的工作/显示了我想用迭代做什么,但我想在流中做这些,而不是使用迭代创建一个中间列表:- 因此,我希望将列表的映射流化到一个列表中,然后在一个流中处理该子列表,而不是必须在两个语句中完成上述操作(即通过迭代构建列表,然后进行流化以筛选/排序和收集)。 到目前为止,我还没有做到这一点,当我尝试流式/收集地图时,我会遇到编译

  • 我想测试我的ViewModel的一个收集流的方法。在收集器内部,一个LiveData对象发生了变化,我希望最后检查它。以下是设置的大致情况: 当我现在在单元测试中调用方法时,测试会在收集流之前完成。这是测试可能会出现的情况: 我正在通过这个Junit5扩展使用TestCoroutineDispatcher,还使用LiveData的即时执行器扩展: