🕷 zenspider.com

by ryan davis



sitemap
Looking for the Ruby Quickref?

Reverse Sort

Published 2012-01-06 @ 15:42

Tagged ruby, thoughts, toys

It’s fairly common knowledge that you can sort and reverse a collection in one pass by using sort_by with a negated number:

1
2
3
4
tally = [["a", 2], ["b", 1], ["c", 2]]

p tally.sort_by { |(str, num)| [-num, str] }
# => [["a", 2], ["c", 2], ["b", 1]]

but what happens if you need to reverse something like strings? Strings don’t respond to unary minus, so you can’t do this:

1
2
tally.sort_by { |(str, num)| [-str, num] } rescue nil
# => undefined method `-@' for "a":String (NoMethodError)

What you want to do is make this behavior dynamic and available everywhere:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module Reversed
  def <=> target
    -super
  end
end

class Object
  def -@
    self.dup.extend Reversed
  end
end

p tally.sort_by { |(str, num)| [-str, num] }
# => [["c", 2], ["b", 1], ["a", 2]]

What would be really special is if Ruby allowed you to apply modules multiple times so that -(-a) == a.