Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deciphering Stream reduce function

Why are both c1 and c2 are not seen as two Strings but instead one String and one Integer?

Arrays.asList("duck","chicken","flamingo","pelican")
            .stream()
            .reduce(0,
                    (c1, c2) -> c1.length() + c2.length(),
                    (s1, s2) -> s1 + s2);
like image 533
alwayscurious Avatar asked Nov 12 '17 04:11

alwayscurious


2 Answers

There are three variations of the reduce method, which differ by their signatures and return types. if you look at the overload for reduce which has this signature:

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

As you can see from the method signature this overload of reduce has 3 parameters the identity, accumulator and a combiner. The identity value is the initial value you've passed into reduce i.e (0), we then have the accumulator which basically incorporates an additional element into a result and finally, the combiner whos job is to combine the two values provided.

so you ask:

Why are both c1 and c2 are not seen as two Strings but instead one String and one Integer?

The first argument to BiFunction is U which in your case is Integer so, therefore, the type used for the identity value must be the same type of the first argument as well as the return type of the accumulator function (BiFunction).

That aside, you'll need to change this:

(c1, c2) -> c1.length() + c2.length()

to this:

 (c1, c2) -> c1 + c2.length()

it's important to note that the combiner function (s1, s2) -> s1 + s2 will not be called at all. Reason being that this specific overload was designed to be used with parallelStream, so in order for a combiner to work, a stream must be parallel. Otherwise, just the accumulator function will be called.

as an side, your full code can be simplified to:

int result = Stream.of("duck","chicken","flamingo","pelican")
                   .reduce(0,
                   (c1, c2) -> c1 + c2.length(),
                   (s1, s2) -> s1 + s2);

or even better if you want to avoid the overhead of boxing/unboxing of reduce:

int result = Stream.of("duck", "chicken", "flamingo", "pelican")
                   .mapToInt(String::length)
                   .sum();
like image 85
Ousmane D. Avatar answered Oct 12 '22 21:10

Ousmane D.


I believe that you are trying to do the following:

Arrays.asList("duck", "chicken", "flamingo", "pelican")
    .stream()
    .map(c -> c.length())
    .reduce((c1, c2) -> c1 + c2);

First, map every String to its length, basically doing the following transformation:

("duck", "chicken", "flamingo", "pelican") -> (4, 7, 8, 7)

Then, reduce that result by adding the values.

like image 44
nicovank Avatar answered Oct 12 '22 22:10

nicovank