1

I'm student and I learning functional Java 8. I got project to do and I don't understand how this function interface work. My teacher told me "you should know that" and I'm looking for help to understand this problem. It should count Fibonacci series

I got this code

StreamUtils.generateRest(Stream.of(1, 1), (a, b) -> a + b)
    .limit(7)
    .forEach(System.out::println);

StreamUtils.generateRest(Stream.of("AAA", "BB", "KKKK"), (a, b) -> a + b)
    .limit(7)
    .forEach(System.out::println);

StreamUtils.generateRest(Stream.of(i -> 0), 
    (BinaryOperator<UnaryOperator<Integer>>) (f, g) -> (x -> x == 0 ? 1 : x * g.apply(x - 1)))
    .limit(10)
    .map(f -> f.apply(7))
    .forEach(System.out::println);

I did something like this but it doesn't work

public class StreamUtils<T> {

    public static <T> Stream generateRest(Stream<T> stream, BinaryOperator<T> binaryOperator) {
        return Stream.of(stream.reduce((a, b) -> binaryOperator.apply(a, b)));
    }

}

Someone can help me with that and explain how to solve this problem?

Ulad
  • 1,083
  • 8
  • 17
  • *but it doesn't work*.. which one of those three implementations are you looking at? Certainly, you're shall be aware that they all are not doing the same thing. – Naman Apr 15 '19 at 16:29
  • I thought first and second run of StreamUtils.generateRest() do same thing –  Apr 15 '19 at 16:36
  • What is the third `generateRest` call supposed to print? The `Stream` only has one element and the `BinaryOperator` ignores the first argument. – Sean Van Gorder Apr 15 '19 at 17:26
  • Here is a solution for fibonacci using Java 8 streams: https://stackoverflow.com/questions/30595844/java-8-lambda-expressions-for-solving-fibonacci-non-recursive-way – Eric Green Apr 15 '19 at 17:38
  • Ok ignore this last one because I also doesn't understand it –  Apr 15 '19 at 17:41
  • 2
    Can you give the expected output for any of them? And should the return type of `generateRest` be `Stream`? Raw types are just going to complicate things. – Sean Van Gorder Apr 15 '19 at 17:48
  • for numbers 1 1 2 3 5 8 13 –  Apr 15 '19 at 18:40

2 Answers2

2

To make first example work you need to implement something like this:

private static class StreamUtils<T> {
    public static <T> Stream generateRest(Stream<T> stream, BinaryOperator<T> binaryOperator) {
        return Stream.iterate(stream.toArray(), p -> new Object[]{p[1], binaryOperator.apply((T) p[0], (T) p[1])})
            .flatMap(p -> Stream.of(p[0]));
    }
}

It creates array from your input stream, then applies passed function on two elements, shifts the result of previous iteration to position 0, as we need previous two values to calculate next. And then it creates unlimited stream of calculated Fibonacci elements.

The output is:

1
1
2
3
5
8
13

And version with correct generics usage, because you initial structure produces raw types.

private static class StreamUtils {
    public static <T> Stream<T> generateRest(Stream<T> stream, BinaryOperator<T> binaryOperator) {
        return Stream.iterate(stream.toArray(), p -> new Object[]{p[1], binaryOperator.apply((T) p[0], (T) p[1])})
            .flatMap(p -> Stream.of((T) p[0]));
    }
}
Ulad
  • 1,083
  • 8
  • 17
  • @anik no idea what should be the output of example #2, if you explain I can try to help, and example #3 doesn't compile – Ulad Apr 15 '19 at 19:49
1

I'm assuming that having more than 2 items means A, B, C, A+B, B+C, C+(A+B), (A+B)+(B+C), etc., and that having 1 item means A, A+A, A+(A+A), (A+A)+(A+(A+A)), etc., where + is the binary operator.

Basically you turn the stream into an array, then you use Stream.generate and at each step you generate the element after the ones you have, shift the array left to fit the new element, and return the old first element (which is no longer in the array). Note that since this has side effects (modifying an external array) it cannot be used with .parallel().

@SuppressWarnings("unchecked")
public static <T> Stream<T> generateRest(Stream<T> stream, BinaryOperator<T> binaryOperator) {
    T[] t = (T[]) stream.toArray();
    if (t.length == 1) {
        t = (T[]) new Object[] { t[0], binaryOperator.apply(t[0], t[0]) };
    }
    final T[] items = t;
    return Stream.generate(() -> {
        T first = items[0];
        T next = binaryOperator.apply(items[0], items[1]);
        System.arraycopy(items, 1, items, 0, items.length - 1);
        items[items.length - 1] = next;
        return first;
    });
}

Output:

1
1
2
3
5
8
13
AAA
BB
KKKK
AAABB
BBKKKK
KKKKAAABB
AAABBBBKKKK
0
0
0
0
0
0
0
0
5040
5040
Sean Van Gorder
  • 3,393
  • 26
  • 26