In our previous post we saw in detail about the foreach. map, flatMap and collect methods in the Iterable trait. In this post we will look into detail about reduceLeft, reduceRight, foldLeft, foldRight methods of the Iterable trait. These methods are almost similar in the way the operate on the collection so it should be easier to study them together.
reduceLeft/reduceRight: The scala doc declares this method as:
reduceLeft[B >: A](op: (B, A) ⇒ B): B
which means that this method accepts a function which takes in 2 parameters and returns one value. And the way this method works is that it applies the operation/passed function on 2 elements at a time starting from left, and result of each application is used to compare with the next element until the end of list.
Lets use this reduceLeft to find out the largest and smallest elements in the collection of numbers:
scala> numbers.reduceLeft((x,a) => if ( x < a ) a else x) res86: Int = 42 //smallest element scala> numbers.reduceLeft((x,a) => if ( x < a) x else a) res87: Int = 2
reduceRight is exactly similar to reduceLeft the only different being reduceRight applies the operation/passed function on the elements starting from the right of the list.
scala> val numbers = List(4,21,2,4,62,345,67) numbers: List[Int] = List(4, 21, 2, 4, 62, 345, 67) //finding maximum scala> numbers.reduceRight((x,v) => if (x > v) x else v) res0: Int = 345 //finding minimum scala> numbers.reduceRight((x,v) => if (x < v) x else v) res1: Int = 2
foldLeft/foldRight: Exactly similar to the way reduceLeft/reduceRight work with a slight difference being foldLeft/foldRight take in an initial value and then apply the initial value to the first element(either leftmost/rightmost) before proceeding like reduceLeft/reduceRight.
Suppose we want to find the sum of the elements in a list (I can use the “sum” method directly, but for understanding I would use foldLeft/reduceLeft):
scala> val numbers = List(1,2,3,4,5,6,7,8,9,10) numbers: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) //initial seed value of 0 gave the correct sum scala> numbers.foldLeft(0)((sum,x) => sum + x) res0: Int = 55 //initial seed value of 10 added 10 to the final sum. scala> numbers.foldLeft(10)((sum,x) => sum + x) res1: Int = 65
One another use of foldLeft is to find the factorial:
//factorial of 5 scala> 1.to(5).foldLeft(1)((prod,x)=>prod*x) res3: Int = 120 //factorial of 6 scala> 1.to(6).foldLeft(1)((prod,x)=>prod*x) res4: Int = 720
scanLeft/scanRight: It functions exactly similar to foldLeft/foldRight, but instead of returning one value these methods return a collection of values. These collection of values are nothing but the intermediate values obtained while the passed function was applied on the list of numbers.
Lets look at the same factorial example using scanLeft/scanRight:
scala> 1.to(6).scanLeft(1)((prod,x)=>prod*x) res5: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 1, 2, 6, 24, 120, 720) scala> 1.to(6).scanRight(1)((prod,x)=>prod*x) res7: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 6, 30, 120, 360, 720, 720)