What is a reducer
The term comes from the world of functional programming, and it's often paired with map
. You've probably heard the term map/reduce if you've been in the programming world for more than a few months.
I won't be talking about map
much in this post because I've already done so in "How to Use the Ruby Map Method". Go read about it there if you want to learn more.
But Ruby is not a functional language you might say, and you would be right. But, Ruby does let you write programs in the functional style through the use of blocks, procs, and lambdas.
Outside of programming, a reducer is defined like this (taken from Wikipedia).
A reducer is the component in a pipeline that reduces the pipe size from a larger to a smaller bore (inner diameter).
But in the programming world, it means reducing a list down to a single value by combining things.
Ruby reduce
In Ruby, the reducer is a method called reduce
.
A popular requirement is to reduce a list of numbers into a single value by adding them together (aka. performing a sum operation).
You can pass the reduce
method a starting value (i.e. 0
in the example below), and a block.
[1, 2, 3].reduce(0) { |sum, n| sum + n } # => 6
The way that works is, for each element of the array, the block gets two arguments. The first argument is the accumulator, the second is the current element. Another way to think about the accumulator is to think about it as a running total.
You can specify the accumulator starting value by passing it as the first argument to reduce
. In the example above, the accumulator starts from 0
. So let's zoom in a little on how that works.
The first time reduce
is executed, sum
is 0
.
0 + 1 # => 1
Now, the next time it runs, the accumulator has a different value (i.e. 1), which it got from the previous iteration.
1 + 2 # => 3
And finally, the last time it runs, the value of the accumulator is 3.
3 + 3 # => 6
So the last value of the accumulator is 6, which is also the value returned by the reduce
method.
Also worth noting is the fact that if you don't specify an initial value for the accumulator, it defaults to the first elemen of the collection.
Ruby inject
The inject method is nothing more than an alias for reduce
. So you can use it exactly as you would use the reduce
method.
[1, 2, 3].inject(0) { |sum, n| sum + n } # => 6
Common reduces
You will find a lot of reduces in the Enumerable
module, but here are some of the most commonly used.
[1, 2, 3].sum # => 6
[1, 2, 3].min # => 1
[1, 2, 3].max # => 2
[1, 2, 3].count # => 3