How many ways are there to sort an array in Ruby?

More than you think…

…even though `Array`

only has two sorting methods (`sort`

& `sort_by`

) these methods can take a block, which allows you to sort in several different ways.

I want to share with you a few examples in this post.

You will also learn how to implement your own sorting method using the quick-sort algorithm.

## Basic Sorting

The most basic form of sorting is provided by the Ruby sort method, which is defined in the Enumerable module.

**Let’s see an example**:

1 2 3 4 5 |
numbers = [5,3,2,1] numbers.sort # [1,2,3,5] |

Notice that `sort`

will return a new array with the results.

It’s also possible to sort “in-place” using the `sort!`

method. This method modifies the current array instead of creating a new one.

## Customized Sorting

Now let’s see more advanced sorting, like being able to sort by string length & things like that.

To do that we can use the `sort_by`

method.

**For example**:

1 2 3 4 5 |
strings = %w(foo test blog a) strings.sort_by(&:length) # [“a”, “foo”, “test”, “blog”] |

It is also possible to do this using the regular `sort`

method with a block.

1 2 3 4 5 |
strings = %w(foo test blog a) strings.sort { |a,b| a.length <=> b.length } # [“a”, “foo”, “test”, “blog”] |

But in general & prefer the `sort_by`

method because the intention is more clear, it’s easier to read & it is also a bit faster.

Note: This`<=>`

symbol is called “the spaceship operator” & it’s a method you can implement in your class. It should return 1 (greater than), 0 (equal) or -1 (less than).

## Reverse Sort

What about sorting in reverse?

You could use the `reverse`

method after sorting, or you can use a block & put a minus sign in front of the thing you are sorting.

**Let me show you an example**:

1 2 3 4 5 |
strings = %w(foo test blog a) strings.sort_by { |str| -str.length } # [“blog”, “test”, “foo”, “a”] |

## Alphanumeric Sorting

Let’s say you want to sort a list of strings that contain numbers.

**Like this**:

1 |
music = %w(21.mp3 10.mp3 5.mp3 40.mp3) |

By default you will not get this list sorted like you want:

1 2 3 |
music.sort # [“10.mp3”, “21.mp3”, “40.mp3”, “5.mp3”] |

But you can fix this using `sort_by`

:

1 2 3 |
music.sort_by { |s| s.scan(/\d+/).first.to_i } # [“5.mp3”, “10.mp3”, “21.mp3”, “40.mp3”] |

I used a regular expression (`\d+`

) to match the numbers, then get the first number (`first`

) & convert it to an integer object (`to_i`

).

## Sorting Hashes

You are not limited to sorting arrays, you can also sort a hash.

**Example**:

1 2 3 4 5 |
hash = {coconut: 200, orange: 50, bacon: 100} hash.sort_by(&:last) # [[:orange, 50], [:bacon, 100], [:coconut, 200]] |

This will sort by value, but notice something interesting here, what you get back is not a hash.

You get a multi-dimensional array when sorting a hash.

To turn this back into a hash you can use the Array#to_h method.

## QuickSort Implementation

Just for fun let’s implement our own sorting method. This is going to be slower than the built-in sort methods, but it’s still an interesting exercise if you like computer science.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def quick_sort(list) qsort_helper(list).flatten end def qsort_helper(list) return [] if list.empty? number = list.sample lower, higher = list.partition { |n| n < number } higher.delete_at(higher.index(number)) [qsort_helper(lower), number, qsort_helper(higher)] end p quick_sort [3, 7, 2, 1, 8, 12] # [1, 2, 3, 7, 8, 12] |

The idea of quick sort is to pick one number at random then divide the list we are sorting into two groups.

One group is the numbers less than the chosen number & the other group is the numbers bigger than the chosen number.

Then we just repeat this operation until the list is sorted.

## Benchmarks

Let’s see how all these sorting methods compare to each other in terms of performance.

Ruby 2.4.0:

1 2 3 4 5 6 |
sort!: 1405.8 i/s sort: 1377.6 i/s - same-ish: difference falls within error sort_by reverse: 196.6 i/s - 7.15x slower sort_by: 183.7 i/s - 7.65x slower sort_by minus: 172.3 i/s - 8.16x slower sort with block: 164.1 i/s - 8.57x slower |

As you can see the regular `sort`

method is a lot faster than `sort_by`

, but it’s not as flexible unless you use a block.

## Summary

You have learned how to use the `sort`

& the `sort_by`

methods to sort your arrays & hashes in different ways. You have also learned about the performance differences & how to implement the quicksort algorithm.