Why You Would Use ‘.sort_by’ Instead of ‘.sort’ in Ruby

Let’s start by reviewing the ‘.sort’ enumerable.

# In case you didn't know, .sort == .sort { |a, b| a <=> b }# using .sort enumerablenumbers_array = [2,1,3,5,4]numbers_array.Sort #=> [1,2,3,4,5]alphabet_array = ["b", "c", "a"]alphabet_array.sort #=> ["a","b","c"]

As shown above, the ‘.sort’ enumerable takes an array and by default sorts the array using ‘< = >’ (spaceship operator). However, you are able to be specific on how you wish to sort the array. For example if you wish to sort the numbers_array from largest to smallest instead of smallest to largest you would do:

numbers_array.sort { |a, b| b <=> a } #=> [5,4,3,2,1]

So now that we have gone over how the traditional ‘.sort’ enumerable works, let’s discuss when & why ‘.sort_by’ is better in a lot of cases.

Similar to ‘.sort’, the ‘.sort_by’ enumerable will sort an array. However, it differs in a couple of ways. Let’s take a look at how you would sort a array of strings by the string length using both ‘.sort’ and ‘.sort_by’

string_array = ["yesterday", "now", "today"]#example using .sort
string_array.sort { |a, b| a.length <=> b.length }
string_array #=> ["now", "today", "yesterday"]
#example using .sort_by
string_array.sort_by { |a| a.length }
string_array #=> ["now", "today", "yesterday"]

The first noticeable difference between the two is that the ‘.sort’ requires two parameters in it’s block, while the ‘sort_by’ block only takes in one.

The second difference is not as clear, however it is much more important. The ‘.sort’ enumerable takes and compares the parameters, comparison by comparison over the entire length of the array. Meanwhile the ‘.sort_by’ takes the single parameter and sorts it using a similar method to the “Schwartzian Transform” (If you want to know more about how the Schwartzian Transform works, i’ve provided links at the bottom of the page to a couple of very helpful resources that go into detail about the subject). To put it simply, in the ‘.sort_by’ enumerable, the comparison is done once at the beginning, where-as in the ‘.sort’ the comparison is calculated for every single comparison between the parameters.

Why does this matter? Well normally it doesn’t make too much of a difference. However, when working with extensive arrays the difference on performance can be quite substantial. This is why I prefer to use the ‘.sort_by’ enumerable when appropriate (also the code just looks cleaner to me).

Just for more clarity on how to use ‘.sort_by’, here’s an example of how it can be used to sort people (which are instance objects of the class Person) in an a array by their age (one of their attributes)

person_array = [bob, george, donna]#bob.age = 39
#george.age = 47
#donna.age = 22
#sort by age using .sort_byperson_array.sort_by {|person| person.age} #=> [donna, bob, george]
Photo by Emile Perron on Unsplash

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store