Home > Enterprise >  Scala: Does reduceLeft and reduceRight have accumulator at different positions?
Scala: Does reduceLeft and reduceRight have accumulator at different positions?

Time:12-02

I am a littlebit confused between the methods reduceleft and reduceRight in Scala. Here's a Snippet that I am testing:

val intList = List(5, 4, 3, 2, 1);
    println(intList.reduceRight((curr, acc) => { //Reduce right me y is accumulator
        println(s"First  Curr = $curr, Acc = $acc")
        curr - acc
    }));
    println(intList.reduceLeft((curr, acc) => { // List(1,2,3,4,5) // Accumulator is the first Element
    println(s"Second Curr = $curr, Acc = $acc")
    acc - curr}))

And the Output is as shown below:

First  Curr = 2, Acc = 1
First  Curr = 3, Acc = 1
First  Curr = 4, Acc = 2
First  Curr = 5, Acc = 2
3
Second Curr = 5, Acc = 4
Second Curr = -1, Acc = 3
Second Curr = 4, Acc = 2
Second Curr = -2, Acc = 1

In both the iterations what I observe is that in case of reduceRight we have (curr,acc) [Meaning curr is passed as first argument and accumulator as second], whereas in case of reduceLeft we have (acc,curr).

Is there any specific reason behind this inconsistency in the arguments?

CodePudding user response:

Let's use a little visualization:

reduceLeft:

                 a  b c d e
  acc1 = f(a, b)  \/ / / /
acc2 = f(acc1, c)  \/ / /
 acc3 = f(acc2, d)  \/ /
  acc4 = f(acc3, e)  \/

reduceRight:

a b c d  e
 \ \ \ \/  acc1 = f(d, e)
  \ \ \/  acc2 = f(c, acc1)
   \ \/  acc3 = f(b, acc2)
    \/  acc4 = f(a, acc3)

The order of arguments help us remember the where the arguments came from and in which order they were evaluated. Because this is quite important to not confuse left-associative and right-associative operations:

  • any visual help matters and writing acc on the correct side of function makes reasoning easier
  • lambdas in coll.reduceLeft(_ operation _) and coll.reduceRight(_ operation _) would have very confusing behavior if acc were on left in both cases

Imagine if you defined a right-associative operator e.g. a ** b (a to the power of b). Exponentiation in math is right-associative, so a ** b ** c should behave like a ** (b ** c). Someone decides to calculate such use case using rightReduce, because it implements exactly this behavior. They do

List(a, b, c).reduceRight(_ ** _)

and then they learn that someone decided that acc should be on left side because they wanted it to be "consistent" with reduceLeft. That would be much more inconsistent with every intuitions that you carried from mathematics.

  • Related