Reducing Your Code Odor With Reduce

Christopher Hague
4 min readMar 24, 2017

--

Tips for Boiling Down Your Code

Meet Mikey:

Mikey

Mikey sells lemonade Monday through Friday. At the end of each day Mikey comes home, counts his quarters and stores the daily earnings in an array. Each index in the array represents the total sales for a given day (index 0 representing Monday, index 4 representing Friday). Let’s take a look at Mikey’s week 1 earnings:

week_1 = [20.75, 22.5, 34, 22, 16.25]

Mikey decides he wants to keep track of his weekly sales in addition to the daily sales. Mikey is new to programming, but he’s figured out a clever way to have his computer do the counting for him. He will use the function below to easily sum the amounts from each day:

def sum_nums(arr)
sum = 0
arr.each do |num|
sum += num
end
sum
end

Mikey will pass theweek_1 array to his method #sum_nums and store the result in a variable called one_week_total:

one_week_total = sum_nums(week_1)
# => 115.5

Congrats to Mikey for figuring out a way to sum his weekly earnings, but what Mikey doesn’t know is that there is already a Ruby method defined to do the same thing. Mikey, meet #reduce:

Mikey and Reduce meet for the first time.

Here is a brief definition of #reduce, borrowed from ruby-doc.org:

Combines all elements of enum by applying a binary operation, specified by a block or a symbol that names a method or operator.reduce { |memo, obj| block } → obj

Let’s see how the code would look had he used the method #reduce to calculate his week one earnings:

one_week_total = week_1.reduce { |sum, num| sum += num }
# => 115.5

Even though passing week_1 to #sum_nums or #reduce will produce the same result, Mikey is a Rubyist, and Rubyist’s like to make their code easy to read AND easy to write. Mikey realizes that he can reduce the size of his Ruby file by a couple of lines if he omits his #sum_nums method.

Invoking Reduce With a Start Value

Mikey crushed it at the stand during his second week of operating. Now Mikey is curious to see the sum of what he has earned over the past 2 weeks. Let’s take a look at his week 2 daily earnings:

week_2 = [35.25, 30.25, 25, 28.75, 37]

Mikey is going to store his two-week total in a variable. Let’s see the code Mikey implements in order to accomplish this:

two_week_total =
week_2.reduce { |sum, num| sum += num } + one_week_total
# => 271.75

Mikey runs his code and discovers that while his program is working just fine, the readability of the code has slightly diminished. Having to add his one_week_total variable to the end of the block is something Mikey would prefer not to see, especially not in a file that he authored himself. #reduce is Mikey’s new favorite method and he was hoping to continue using it to sum his earnings. Mikey fears that the quality of his code will suffer if he continues to use #reduce. Poor Mikey.

Mikey is crying, but doesn’t want anyone to see

Luckily for us, Mikey is resilient and reminds himself that he has been running a lemonade stand for two whole weeks. If he can manage that, then surely he can find a way to continue using the #reduce method while maintaining the readability of his code. After many seconds of sleuthing on Google, Mikey discovers that #reduce can be invoked with a start value. This makes Mikey happy.

Mikey is happy again

Let’s reimplement the code written above and pass one_week_total as a start value to Mikey’s summation:

two_week_total =
week_2.reduce(one_week_total) { |sum, num| sum += num }
# => 271.75

By passing an argument to #reduce, the summing of the collection will start at the value passed rather than starting at 0. Including this start value enables Mikey to conveniently find the total sum of his reduced value from week 2 by adding it to his one_week_total — all without having to sacrifice the readability of his code. He can even use it to sum this month’s earnings with next month’s!

monthly_total = week_4.reduce(three_week_total) {|sum,num| sum += num}

Go Mikey!

--

--