In Ruby 1.9, Hash
es are sorted, but Hash#sort
still returns an Array
of Array
s. Imagine that! It does imply that you can build your own sorting method on top of it.
class Hash
def sorted_hash(&block)
self.class[sort(&block)] # Hash[ [[key1, value1], [key2, value2]] ]
end
end
Hash
es are unsorted in Ruby 1.8. If you want Ruby 1.8 compatibility, you can use ActiveSupport's OrderedHash
. It behaves like a 1.9-Hash
, so you can define the same sorted_hash
method on it:
class ActiveSupport::OrderedHash
def sorted_hash(&block)
self.class[sort(&block)]
end
end
hash = ActiveSupport::OrderedHash.new
hash["b"] = "b"
hash["a"] = "a"
hash #=> {"b"=>"b", "a"=>"a"} => unsorted
hash.sorted_hash #=> {"a"=>"a", "b"=>"b"} => sorted!
You have to copy the sorted_hash
method to your code, because it does not exist by default!
Update for deep sorting:
If you're looking to sort on something else than the hash key, pass a block to the sorted_hash
method as follows (assuming the implementation from above):
hash = ActiveSupport::OrderedHash.new
hash["a"] = { "attr" => "2", "..." => "..." }
hash["b"] = { "attr" => "1", "..." => "..." }
# Unsorted.
hash
#=> {"a"=>{"attr"=>"2", "..."=>"..."}, "b"=>{"attr"=>"1", "..."=>"..."}}
# Sort on the "attr" key. (Assuming every value is a Hash itself!)
hash.sorted_hash { |a, b| a[1]["attr"] <=> b[1]["attr"] }
#=> {"b"=>{"attr"=>"1", "..."=>"..."}, "a"=>{"attr"=>"2", "..."=>"..."}}