Basic Sorting in Ruby
Fast recall
Quick revision
Core answer
Array#sort returns a sorted copy, while sort! changes the receiver. Both use the elements' <=> comparison by default or a block that returns a negative number, zero, or a positive number. sort_by computes one key per element and sorts by those keys, which is clearer and often more efficient when key calculation is non-trivial. For interview analysis, treat general comparison sorting as O(n log n), while noting Ruby's documentation does not promise one specific sorting algorithm or stability guarantee.Whether you know Ruby's sort is O(n log n) built-in, sort_by for a key, and can name the O(n^2) sorts (bubble/insertion/selection).
Writing a hand-rolled O(n^2) sort in real code (use the built-in sort_by), or confusing sort (a<=>b) with sort_by (key).
Ruby's sort/sort_by is O(n log n) built-in; sort_by { |x| key } for a key. O(n^2) sorts (bubble/insertion/selection) for interviews; use sort_by in code.
Interview-ready guide
Interview answer
Ruby arrays provide sort, sort!, sort_by, and sort_by!. sort leaves the original array unchanged and returns an ordered array; sort! replaces the receiver's order. Without a block, elements are compared through <=> and must be mutually comparable.
A sort block receives two elements and returns a negative value, zero, or a positive value. It is useful for direct comparisons such as descending numeric order. sort_by is better when each object has a key, because the block computes that key once per element and Ruby sorts the decorated values.
For example, users.sort_by { |user| [-user.score, user.name] } orders higher scores first and uses name as a deterministic tie-breaker. The array key is compared lexicographically, so the rule is visible without a long comparator block.
General comparison sorting is described as O(n log n) in normal interview analysis, plus O(n) key extraction for sort_by. Expensive comparison or key work affects the real cost. Ruby documentation does not make sorting stability a portable contract, so equal keys need an explicit secondary key when order matters.
I choose mutation only when the method owns the array and callers expect its order to change. Otherwise sort or sort_by gives a safer boundary. I also test duplicate keys, nil or mixed values, and ascending versus descending direction instead of assuming <=> can compare every input.
Basic Sorting in Ruby
Direct Answer
Array#sort returns a sorted copy, while sort! changes the receiver. Both use the elements' <=> comparison by default or a block that returns a negative number, zero, or a positive number. sort_by computes one key per element and sorts by those keys, which is clearer and often more efficient when key calculation is non-trivial. For interview analysis, treat general comparison sorting as O(n log n), while noting Ruby's documentation does not promise one specific sorting algorithm or stability guarantee.
Deep Dive & Architecture
An ordering policy must define how any relevant pair relates. Ruby's spaceship operator expresses less than, equal in ordering, or greater than. A comparator that contradicts itself can produce meaningless results, and a nil comparison signals values that do not share a valid ordering.
Key extraction simplifies that policy. A record can be mapped to [priority, created_at, id], and Array comparison applies each field until a difference appears. Adding a stable unique field at the end makes ties deterministic without relying on the sort implementation to preserve input order.
sort_by uses extra memory to associate elements with computed keys. That trade is valuable when extracting the key is expensive because a comparator may otherwise repeat the work many times. For a trivial numeric reverse order, a direct comparator or an extracted negative key can both be readable.
Sorting changes the problem's information. It enables binary search and monotonic pointer movement, but it can remove original positions and costs more than a linear scan. Before sorting, ask whether the required output needs input order, original indices, or only the ordered values.
Code Example
User = Struct.new(:name, :score)
users = [
User.new('Mina', 8),
User.new('Ari', 10),
User.new('Zoe', 10)
]
ranked = users.sort_by { |user| [-user.score, user.name] }
raise unless ranked.map(&:name) == ['Ari', 'Zoe', 'Mina']
raise unless users.map(&:name) == ['Mina', 'Ari', 'Zoe']
numbers = [3, 1, 2]
numbers.sort!
raise unless numbers == [1, 2, 3]
Common Mistakes & Pitfalls
Writing a hand-rolled O(n^2) sort in real code (use the built-in sort_by), or confusing sort (a<=>b) with sort_by (key).
Check your understanding
Answer these without looking back at the article.
- Why can `sort_by` avoid repeated expensive key calculation?
- How do compound keys create deterministic tie-breaking?
- Why should Ruby code not rely on sorting equal keys being stable?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.