Why does the new JDK8 Stream
class contain only the following reduce
methods:
T reduce(BinaryOperator<T> reducer)
T reduce(T identity, BinaryOperator<T> reducer)
U reduce(U identity, BiFunction<U, ? super T, U> reducer,
BinaryOperator<U> combiner)
but not an obvious method which corresponds to reduce
/fold
functions found in other languages (e.g. Haskell foldl :: (a -> b -> a) -> a -> [b] -> a
) and which could look like this:
U reduce(U identity, BiFunction<U, ? super T, U> reducer)
?
Instead there is a similar method which has an extra combiner
argument. I'm not even sure how to use it since the API documentation I linked to above does not use this argument in the example, it only mentions its required properties.
Why are the JDK8 methods made like this, and how can I emulate standard fold
behavior with them?
The reduce
-like data-parallel operations serve as general value-aggregation operations over a data set (e.g. an array of elements). You can use them to implement, for example, the sum.
The order in which the values of the data set are combined together (e.g. summed) is not specified, so they do not correspond to foldl
found in Haskell or reduceLeft
/foldLeft
found in Scala.
The extra combiner
argument in the third line is used when the result type of the aggregation is different than the type of your elements. In these cases you have to specify how to combine two results together.
Lets say you want to implement a count of vowels in a string using the third reduce. The data elements are characters and the reducer
specifies how a character and the current count are combined:
(Integer count, Character c) -> if (isVowel(c)) count + 1 else count
The combiner will just be a sum:
(Integer count1, Integer count2) -> count1 + count2
Scala Parallel Collections, for example, has these for a while now (search for aggregate
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With