替代仅过滤匹配某个元素

时间:2018-05-12 15:59:46

标签: java java-8 functional-programming java-stream

我正在考虑替换remove(int index)remove(T element)的List方法。我在哪里获取一个列表并进行一些过滤并返回一个新列表,而不要求删除该元素。我想在功能上做到这一点,因为我不想改变原始列表。

这是我的尝试。

List<Integer> integers = Arrays.asList(2, 4, 1, 2, 5, 1);
Integer elementToRemove = 1;
List<Integer> collect = 
           integers.stream()
                   .filter(elements -> !elements.equals(elementToRemove))
                   .collect(Collectors.toList());

这将删除所有1。

我不会只删除第一个1,因此我会留下像[2,4,2,5,1]

这样的列表

我知道如何使用indexOf()sublist()以及addAll()来完成此操作。但我觉得这不如使用溪流那么好。

寻找使用流实现remove(int index)remove(T element)的功能性解决方案。

2 个答案:

答案 0 :(得分:2)

我同意@Aominè,但这可以作为流API的替代方案

IntStream.range(0,integers.size())
           .filter(i->i != integers.indexOf(elementToRemove)) 
           .mapToObj(i->integers.get(i))
           .collect(Collectors.toList());

由于@Aominè评论优化,首先找到elementToRemove的索引,然后在过滤器中使用它。

答案 1 :(得分:1)

虽然我的另一个答案肯定是我推荐的方式,而@Hadi也提供了“流”替代方案,它也是有效的。我决定使用不同的方法来使用JDK-8的功能来实现相同的结果。

在JDK-9中有一个takeWhiledropWhile方法,前者返回一个流,该流包含从与给定谓词匹配的流中获取的元素的最长前缀。

后者在删除与给定谓词匹配的最长元素前缀后,返回由给定流的剩余元素组成的流。

这里的想法是消耗元素而不等于elementToRemove

integers.stream()
        .takeWhile(e -> !Objects.equals(e, elementToRemove))

并删除元素,但不等于elementToRemoveskip(1)以排除elementToRemove

integers.stream()
        .dropWhile(e -> !Objects.equals(e, elementToRemove))
        .skip(1)

因此产生两个流,其中第一个流是所有前面的数字到elementToRemove,第二个流加上skip(1)elementToRemove之后的所有元素然后我们只是将它们连接起来收集到列表实现。

List<Integer> result = Stream.concat(integers.stream()
                        .takeWhile(e -> !Objects.equals(e, elementToRemove)),
                integers.stream()
                        .dropWhile(e -> !Objects.equals(e, elementToRemove))
                        .skip(1))
                .collect(Collectors.toList());

假设列表中不存在要删除的元素,takeWhile将使用所有元素,dropWhile将删除所有元素,当我们合并这两个流时,我们返回初始元素

总的来说,这将取得与其他答案相同的结果。

但是,不要在生产代码中使用此解决方案,因为它不是最理想的,并且不明显代码的作用。它只是在这里展示完成上述要求的不同方法。