As you can imagine to generate a specific Fibonacci number in this sequence, the previous two numbers are required, which means the state of the previous two numbers need to be maintained somewhere. The two solutions that I will be describing here both maintain this state, however they do it differently.
Mutable State
In the first approach, I am just going to maintain state this way:
class FibState { private long[] prev = new long[2]; private int index = 0; public long nextFib() { long result = (index == 0) ? 1 : ((index == 1) ? 1 : prev[0] + prev[1]); prev[0] = prev[1]; prev[1] = result; index++; return result; } }
with index keeping track of the index of the current fibonacci number in the sequence and prev capturing the most recent two in the sequence. So the next in the series is generated by mutating the index and the changing the array holding the recent values. So given this state, how do we generate the stream, using code which looks like this:
Stream<Long> streamOfFib() { FibState fibState = new FibState(); return Stream.generate(() -> fibState.nextFib()); }
Immutable State
class FibState { private final long[] prev; private final int index; public FibState() { this(new long[]{-1, 1}, 0); } public FibState(long[] prev, int index) { this.prev = prev; this.index = index; } public FibState nextFib() { int nextIndex = index + 1; long result = (nextIndex == 1) ? 1 : prev[0] + prev[1]; return new FibState(new long[]{prev[1], result}, nextIndex); } public long getValue() { return prev[1]; } }Instead of mutating the state, it returns the next immutable state. Alright, so now that this version of state is available, how can it be used - by using the "iterate" function of Stream, like this:
Stream<Long> streamOfFib() { return Stream .iterate(new FibState(), fibState -> fibState.nextFib()) .map(fibState -> fibState.getValue()); }
this function takes two parameters - the initial state and something which can generate the next state. Also to return numbers from it, I am mapping this "state" type to a number in the "map" operation.
Conclusion
This is generally instructive on how to generate a stream using Fibonacci sequence as an example. The approach will be fairly similar for any stream that you may need to generate. My personal preference is for the Immutable state variation as that delegates most of the mechanism of generating the stream to the excellent "iterate" helper function of Stream.
No comments:
Post a Comment