【问题标题】:Providing Limit condition on Stream generation [duplicate]提供流生成的限制条件[重复]
【发布时间】:2014-03-06 04:29:58
【问题描述】:

我正在编写一个代码来计算斐波那契数。使用此代码,我可以生成斐波那契数列的前 n 个数字。

Stream.generate(new Supplier<Long>() {
    private long n1 = 1;
    private long n2 = 2;

    @Override
    public Long get() {
        long fibonacci = n1;
        long n3 = n2 + n1;
        n1 = n2;
        n2 = n3;
        return fibonacci;
    }
}).limit(50).forEach(System.out::println);

limit 方法返回 Stream,其中包含传递给此方法的元素数量。我想在斐波那契数达到某个值后停止生成Stream

我的意思是,如果我想列出所有小于 1000 的斐波那契数,那么我不能使用 limit,因为我不知道可能有多少斐波那契数。

有没有办法使用 lambda 表达式来做到这一点?

【问题讨论】:

    标签: java lambda java-8 java-stream


    【解决方案1】:

    如果你不介意使用迭代器,你可以写成:

    static LongUnaryOperator factorial = x -> x == 0 ? 1
                                          : x * factorial.applyAsLong(x - 1);
    
    public static void main(String[] args) {
        LongStream ls = LongStream.iterate(0, i -> i + 1).map(factorial);
        OfLong it = ls.iterator();
        long next = 0;
        while ((next = it.nextLong()) <= 1000) System.out.println(next);
    }
    

    【讨论】:

      【解决方案2】:

      使用Stream 的内置功能我能找到的最佳解决方案是:

      LongStream.generate(new LongSupplier() {
        private long n1 = 1, n2 = 2;
      
        public long getAsLong() {
            long fibonacci = n1;
            long n3 = n2 + n1;
            n1 = n2;
            n2 = n3;
            return fibonacci;
        }
      }).peek(System.out::println).filter(x->x>1000).findFirst();
      

      它的缺点是处理第一个项目是&gt;=1000。这可以通过使语句有条件来防止,例如

      .peek(x->{if(x<=1000) System.out.println(x);}).filter(x->x>1000).findFirst();
      

      但我不喜欢对相同的条件(大于或不大于千)进行两次评估。但是,对于需要基于结果值的限制的现实生活中的任务,这两种解决方案中的一种可能足够实用。

      我认为,很明显整个构造不具备并行能力……

      【讨论】:

        【解决方案3】:

        是的,有一种 lambda 方式,但不幸的是,我认为它没有在当前的 Java 8 Stream API 中实现。 很抱歉为您指出另一种语言,但我认为您想要的是类似

         takeWhile(p: (A) ⇒ Boolean): Stream[A]
        

        来自 Scala Stream API。

        因为这在 Java API 中没有实现,所以你必须自己做。 这个怎么样:

        public static List<T> takeWhile(Iterable<T> elements, Predicate<T> predicate) {
           Iterator<T> iter = elements.iterator();
           List<T> result = new LinkedList<T>();
           while(iter.hasNext()) {
             T next = iter.next();
             if (predicate.apply(next)) {
               result.add(next);
             } else {
               return result;  // Found first one not matching: abort
             }
           }
           return result;  // Found end of the elements
        }
        

        然后你可以像这样使用它

        List<Long> fibNumbersUnderThousand = takeWhile(allFibNumStream, l -> l < 1000);
        

        (假设 StreamIterable 的一个实例 - 如果不是,您可能需要调用 .iterator() 方法并将其包装起来)

        【讨论】:

          【解决方案4】:

          肮脏的第一个版本

                  Stream.generate(new Supplier<Long>() {
                  private long n1 = 1;
                  private long n2 = 2;
          
                  @Override
                  public Long get() {
                      long fibonacci = n1;
                      long n3 = n2 + n1;
                      n1 = n2;
                      n2 = n3;
                      return fibonacci;
                  }
              }).limit(50).forEach(x -> {
                  if (x < 1000) {
                      System.out.println(x);
                  }
              });
          

          【讨论】:

          • 啊我真的不能打电话给System.exit :-(
          • 我不喜欢我使用 System.exit(0) 的方式;在这里,但它确实完成了工作。
          • 好吧,我们组合一个我们知道的限制太大了,只控制它的打印量,我不知道有什么其他方法可以结束一个 streat(java8 的新手)
          猜你喜欢
          • 1970-01-01
          • 2012-04-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多