Providing a limit condition for stream generation

I am writing code to calculate Fibonacci numbers. With this code, I can generate the first n numbers of the Fibonacci sequence.

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

The limit method returns a Stream , which contains the number of elements passed to this method. I want to stop the generation of Stream after the Fibonacci number reaches a certain value.

I mean, if I want to list all Fibonacci numbers less than 1000, then I can not use limit , because I do not know how many Fibonacci numbers could be.

Is there a way to do this using lambda expressions?

+2
source share
4 answers

If you don't mind using an iterator, you can write it as:

 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); } 
+3
source

The best solution using Stream s built-in features can be found:

 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(); 

The disadvantage is that the processing of the first element will be >=1000 . This can be prevented by making the expression conditional, for example

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

but I do not like to evaluate the same condition (more than thousands or not) twice. But perhaps one of these two solutions can be practical enough for real-world tasks where a limit based on the resulting value is needed.

I think it’s clear that the whole structure is not parallel ...

+3
source

Yes, there is a lambda way, but, unfortunately, I do not think that it is implemented in the current Java 8 Stream API. Sorry to point to another language, but what I think you want is something like

  takeWhile(p: (A) β‡’ Boolean): Stream[A] 

from the Scala Stream API.

Since this is not implemented in the Java API, you must do it yourself. How about this:

 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 } 

Then you can use it as

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

(Assuming Stream is an Iterable instance - if not, you might need to call the .iterator() method and end it)

+2
source

Dirty first version

  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); } }); 
+1
source

Source: https://habr.com/ru/post/1204380/


All Articles