Ruby reduce method usage example
Reduce method can be used to reduce a set of values to a single number / variable by performing some operation on an individual element. If unaware, you may end up using iterations such as each, map, sum to obtain the result. This tutorial illustrates how we can use reduce appropriately.
Today, I was working on an optimization work on one of the Ruby on Rails project. There was an issue with sum displayed on the consumer side.
I started debugging by finding out the controller action which returns the response that was being displayed on the UI. The value that was getting displayed on the front-end was 0. I was expecting it to be some value instead of 0.
Let’s see the example of the scenario. Let’s say, we have review score for the category of products. While debugging I came across this piece of code.
Now, the method total_score
was returning output as 0
.
Can you try and find out the reason why it could return value 0
by looking at the method total_score
again?
Incorrect usage of slice
Yes, the slice method is used incorrectly in total_score
method.
The method total_score
performs following actions.
- slice key value pairs from
category_wise_review_score
having keys as category IDs - Get the values from resulting hash
- Convert the invidual element into an array using map
- Sum the values from resultant array
And return the response.
I checked out git history to see why this change was done this way. I found out the older implementation as below.
Basically, it did not have category_ids
method,
instead it has cateogries
method which returned ActiveRecord collection.
And, total_score
method called categories
method and performed each
operation which performed query like,
So, we understand from this that,
Author wanted to avoid selecting all columns from categories when querying.
As calling,
just performs a query on id
column of the categories as given below.
The author was right to avoid selecting unnecessary columns
to be not used when querying categories
.
So, where was the problem?
The problem was in the usage of slice method.
slice
expects comma separated values to be sliced.
Thus, array argument needs be passed as *category_ids
as given below.
This fixes the behavior and returns an expected total_score
.
Can we still improve?
Yes, the way query was avoided by using Ruby methods such as,
slice
, values
, map
and sum
was just unnecessary.
Calling all these methods introduces 4 iterations on the hash.
Thus, thing to learn from this:
Less is not always better
Don’t just go for one liners as a part of code optimization.
The total_score
method was changes as given below.
tl;dr;
There is more than one way to achieve what we want in Ruby. Try and know Ruby / Rails methods and understand when they can be used appropriately to avoid such issues.
Subscribe to Ruby in Rails
Get the latest posts delivered right to your inbox