The reduceLeft
method on the Scala collections is fun. Just start with a collection:
scala> val a = Array(20, 12, 6, 15, 2, 9) a: Array[Int] = Array(20, 12, 6, 15, 2, 9)
Then give reduceLeft
a simple function to work with, and let it do its thing:
scala> a.reduceLeft(_ + _) res0: Int = 64 scala> a.reduceLeft(_ * _) res1: Int = 388800 scala> a.reduceLeft(_ min _) res2: Int = 2 scala> a.reduceLeft(_ max _) res3: Int = 20
Use a function
When your comparison operation gets long, just create a function first, then pass the function into reduceLeft
:
scala> val a = Array(20, 12, 6, 15, 2, 9) a: Array[Int] = Array(20, 12, 6, 15, 2, 9) scala> val f = (x:Int, y:Int) => x max y f: (Int, Int) => Int = <function2> scala> a.reduceLeft(f) res0: Int = 20
Admittedly that was a simple function, but we'll look at a longer one next.
How reduceLeft works
The reduceLeft
method words by applying the function/operation you give it, and applying it to successive elements in the collection. The result of the first comparison is used in the second comparison, and so on. It works from left to right, beginning with the first element in the collection.
We can demonstrate this by creating a bigger function now. We'll do a max
comparison like we did earlier, but now we'll add some debugging code to the function so we can see how reduceLeft
works. Here's the function:
// returns the max of the two elements def findMax(x: Int, y: Int): Int = { val winner = x max y println("compared %d to %d, %d was larger".format(x,y,winner)) winner }
Next, let's move the numbers in the array around a little bit, so the output will be more interesting:
val a = Array(12, 6, 15, 2, 20, 9)
Now we call reduceLeft
on our new array, giving it our new function, and we see how reduceLeft
works:
scala> a.reduceLeft(findMax) compared 12 to 6, 12 was larger compared 12 to 15, 15 was larger compared 15 to 2, 15 was larger compared 15 to 20, 20 was larger compared 20 to 9, 20 was larger res0: Int = 20
Boo-yah! Here's how the process worked:
reduceLeft
started by callingfindMax
to test the first two elements in the array, andfindMax
returned 12 (because 12 is larger than 6).reduceLeft
took that result (12), and calledfindMax(12, 15)
. 12 was the result of the first comparison, and 15 is the next element in the collection. 15 is larger, so it became the new result.reduceLeft
kept taking the result from the function and comparing it to the next element in the collection, until it marched through all the elements in the collection and ended up with the number 20.reduceLeft
doesn't know it's finding the largest element in the collection. It just marches through the collection, using the function you provide to (a) compare one element to the next, (b) get the result, then (c) compare that result to the next element in the collection, again using your function to perform the comparison.
One subtle but important note that we just saw: Your function must return the same data type that's stored in the collection. This is necessary so reduceLeft
can compare that result to the next element in the collection.
Working with other collection types
The collection can be any sequence, including List
, Array
, Vector
, Seq
, and more. The type of collection can be anything you need. For instance, determining the longest or shortest string in a collection of strings is also pretty easy:
scala> val peeps = Vector("al", "hannah", "emily", "christina", "aleka") peeps: scala.collection.immutable.Vector[java.lang.String] = Vector(al, hannah, emily, christina, aleka) // longest scala> peeps.reduceLeft((x,y) => if (x.length > y.length) x else y) res0: java.lang.String = christina // shortest scala> peeps.reduceLeft((x,y) => if (x.length < y.length) x else y) res1: java.lang.String = al
Just take a similar approach with your own data types, and you can use Scala's reduceLeft
collection method to handle all sorts of problems like this.
Summary
If you were wondering how Scala's reduceLeft collections method worked, I hope these examples have been helpful.