Passing a collection using the reduce function (3 parameters) - java 8 threads

I am trying to calculate the multiplication of a value using the previous two values ​​using a java 8 stream. I want to call a function that will return an array / list / collection. I create a list and add 1.2 to it.

Let's say the list name is the result.

public static void main (String[] args) { List<Integer> result = new ArrayList<Integer>(); result.add(1); result.add(2); int n = 5; //n can be anything, choosing 5 for this example res(n, result); //print result which should be [1, 2, 2, 4, 8] } public static List<Integer> res(int n, List<Integer> result ) { result.stream() .limit(n) .reduce(identity, (base,index) -> base); //return result; } 

Now the problem is trying to pass the result to the stream in order to update the list with the new values ​​using the stream. According to java tutorials, this is possible, albeit inefficient.

"If your reduction operation involves adding items to the collection, then each time your battery function processes the item, it creates a new collection that contains the item that is inefficient.

Do I need to use the optional third parameter BinaryOperator combiner to combine the list + result?

 <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner) 

Shortly speaking; I want to pass a list with two values ​​and find a function to multiply the first two values ​​(1,2), add them to the list and find the multiplication of the last two values ​​(2,2) and add this to the list, and until the stream reaches the limit.

+6
source share
2 answers

It looks like you are trying to implement a recursive relation. The reduce method applies a function to a collection of pre-existing values ​​in a stream. You cannot use reduce and take the intermediate result from the reducer function and “return it back” to the stream, what you need to do to implement the recursive relation.

A way to implement a recursive relationship using streams is to use one of the factory streams of the Stream.generate or Stream.iterate . iterate factory seems to offer the most obvious approach. The state that should be stored for each application of the repeat function requires two integers in your example, so, unfortunately, we need to create an object to store this data for us:

 static class IntPair { final int a, b; IntPair(int a_, int b_) { a = a_; b = b_; } } 

Using this state object, you can create a thread that implements the required repetition:

 Stream.iterate(new IntPair(1, 2), p -> new IntPair(pb, pa * pb)) 

Once you have such a stream, just collect the values ​​into a list:

 List<Integer> output = Stream.iterate(new IntPair(1, 2), p -> new IntPair(pb, pa * pb)) .limit(5) .map(pair -> pair.a) .collect(Collectors.toList()); System.out.println(output); [1, 2, 2, 4, 8] 

As an aside, you can use the same method to generate the Fibonacci sequence. All you do is another initial value and an iterative function:

 Stream.iterate(new IntPair(0, 1), p -> new IntPair(pb, pa + pb)) 

You can also implement a similar recursive relation using Stream.generate . This will also require a helper class. The helper class implements the Supplier value of the result, but it must also maintain state. Therefore, it must be volatile, which is rude in my book. The iteration function must also be baked into the generator object. This makes it less flexible than an IntPair object, which can be used to create arbitrary repetitions.

+11
source

Just for completeness, here is a solution that does not need an extra class.

 List<Integer> output = Stream.iterate( (ToIntFunction<IntBinaryOperator>)f -> f.applyAsInt(1, 2), prev -> f -> prev.applyAsInt((a, b) -> f.applyAsInt(b, a*b) ) ) .limit(9).map(pair -> pair.applyAsInt((a, b)->a)) .collect(Collectors.toList()); 

This is a functional approach that does not require intermediate storage of values. However, since Java is not a functional programming language and does not have optimizations for such a definition of a recursive function, this is not recommended for large threads.

Since for this example, a larger stream will still overflow, and the calculation will be cheap, this approach will work. But for other use cases, you will certainly prefer a storage object when solving such a problem with plain Java (as in Stuart Marks answer )

+4
source

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


All Articles