sort_by method

The sort_by method takes an enumerable collection and returns sorted list, much the way sort does. The main difference is that it's much more efficient for complex comparisons. You must specify a block, and it will only be run once for each item in the collection. By contrast, sort runs the block multiple times per item, as it compares various items to each other.

The magic of sort_by is that it stores the return value of the given block for each item in the collection, then does all the comparison sorting on those return values directly.

Number List

@numbers = [1, 0, 3, 2, 5, 4, 7, 6, 9, 8]

# numbers sorted:
@numbers.sort_by{|number| number}
    #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# numbers sorted by negative values:
@numbers.sort_by{|number| 0 - number}
    #=> [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Pet Inventory

For simple comparisons like sorting by quantity below, the performance of sort_by is very close to that of sort. In fact, sort should be used in simple cases, as it's more efficient:

# sorting pets by quantity:
@inventory.sort_by(&:quantity).map(&:name)
    #=> ["rock", "scorpion", "monkey", "cat", "dog", "fish", "beetle"]
    
# all the comparisons required to sort:
#    dog
#    cat
#    fish
#    scorpion
#    beetle
#    monkey
#    rock

# total comparisons: 7
# total time: 0.0001 seconds

However, more complex comparisons will benefit from sort_by:

# sorting pets by time-consuming secret code:
@inventory.sort_by{|pet| pet.secret_code }
    #=> ["beetle", "dog", "scorpion", "monkey", "rock", "fish", "cat"]
    
# all the comparisons required to sort:
#    342116e7
#    bfb82661
#    b0d58a4b
#    3acf0f48
#    1dd19813
#    4a8b41d6
#    a4977713

# total comparisons: 7
# total time: 1.8045 seconds

Even with a collection of only seven items, this took over three times as long using sort.

Leave a Reply

Your email address will not be published. Required fields are marked *