首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何过滤掉只有第一个不匹配Java顺序流中的谓词的元素?

如何过滤掉只有第一个不匹配Java顺序流中的谓词的元素?
EN

Stack Overflow用户
提问于 2018-03-02 00:16:31
回答 2查看 0关注 0票数 0

我在Java流操作中遇到了一个边缘案例...

我想编码以下行为:“从任意一篮子水果中,收集最小的20个,除了最小的梨子,因为我们不需要这个。”

额外的奖励:来的篮子可能根本没有任何梨。

例子 :

  • 从[梨5,苹果1,苹果2,苹果10,梨3,梨7],我们想要[苹果1,苹果2,梨5,梨7,苹果10]。
  • 从[苹果4,苹果7,梨8,梨2,梨3],我们想要[梨3,苹果4,苹果7,梨8]。

到目前为止,我在这一步:

代码语言:javascript
复制
output = basket.stream()
    .sorted(Comparator.comparing(Fruit::getSize))
    //.filter(???)
    .limit(20)
    .collect(fruitCollector);

这看起来像是一个有状态的 lambda过滤器,我不知道该怎么做。

我不能使用本地firstPear布尔值,并将其设置为true过滤第一个梨之后,因为lambda中的所有局部变量都必须是最终的。

最糟糕的情况是,我可以把篮子分成两个,梨子和非梨子,把梨子分类,如果有的话,将它们分类。这看起来非常低效和丑陋。有没有更好的办法?

我组装了一个小型测试工具来比较这些算法的性能。

这个比较没有我想要的那么广泛 - 已经有3周了。它仅涵盖顺序处理简单项目的用法。随意给测试设备一个去,并添加更多的测试,更多的基准或自己的实现。

我的分析:

代码语言:javascript
复制
算法| 作者| Perf | 注释
--------------------------------------------------------------------------------
索引删除| Holger | 最佳| 最好的整体,有点模糊
有状态谓词| pedromss | 最佳| 不要用于并行处理
直截了当的方法| Misha | 最佳| 当少数元素匹配时更好
自定义收集器| 尤金| 好| 当全部或者没有元素匹配时更好
Comaprator hack w / dummy | yegodm | 好|  - 
比较黑客| xenteros | * | 对输出大小敏感的Perf在边缘情况下失败。

由于它的良好性能和“黑盒子”功能(状态管理代码位于外部类中,贡献者可以专注于业务逻辑),因此我获得了很好的答案,因为它是我们在项目中实施的答案。 )。

请注意,接受的答案可能不是最适合您的:查看其他人,或者查看我的测试项目以亲自查看。

EN

回答 2

Stack Overflow用户

发布于 2018-03-02 08:30:18

你可以使用有状态的谓词:

代码语言:javascript
复制
class StatefulPredicate<T> implements Predicate<T> {

    private boolean alreadyFiltered;
    private Predicate<T> pred;

    public StatefulPredicate(Predicate<T> pred) {
        this.pred = pred;
        this.alreadyFiltered = false;
    }

    @Override
    public boolean test(T t) {
        if(alreadyFiltered) {
            return true;
        }

        boolean result = pred.test(t);
        alreadyFiltered = !result;
        return result;
    }
}

    Stream.of(1, -1, 3, -4, -5, 6)
        .filter(new StatefulPredicate<>(i -> i > 0))
        .forEach(System.out::println);

打印: 1, 3, -4, -5, 6

如果并发是一个问题,您可以使用原子布尔值。

如果您希望跳过多于1个元素,请将该参数添加到您的构造函数中并在其中构建逻辑 StatefulPredicate

此谓词过滤掉第一个负面元素,然后让其他元素通过,无论如何。在你的情况下,你应该测试instanceof Pear

由于人们对过滤器无国籍表示担忧,从文档:

中间业务进一步分为无状态和有状态操作。无状态操作(如过滤器和映射)在处理新元素时不会保留先前看到的元素的状态 - 每个元素都可以独立于其他元素上的操作进行处理。有状态的操作(如独立和排序)可以在处理新元素时结合之前看到的元素的状态。

该谓词不保留有关先前看到的元素的信息。它保留有关以前结果的信息。

也可以使线程安全以避免并发问题。

票数 0
EN

Stack Overflow用户

发布于 2018-03-02 09:48:33

你有没有考虑过简单的方法?找到最小的梨,过滤掉(如果存在)并收集20个最小的梨:

代码语言:javascript
复制
Optional<Fruit> smallestPear = basket.stream()
        .filter(Fruit::isPear)  // or whatever it takes to test if it's a pear
        .min(Fruit::getSize);

Stream<Fruit> withoutSmallestPear = smallestPear
        .map(p -> basket.stream().filter(f -> f != p))
        .orElseGet(basket::stream);

List<Fruit> result = withoutSmallestPear
        .sorted(comparing(Fruit::getSize))
        .limit(20)
        .collect(toList());
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100007479

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档