I have the following hash:
user = {
'user' => {
'title' => {'weight' => 1, .... }
'body' => {'weight' => 4, ....}
....
....
}
}
Is is possible to get the User sorted by the weight key of its child hashes?
I looked in the Hash.sort, but it looks like it returns array rather than my original hash sorted.
In Ruby 1.9, Hashes are sorted, but Hash#sort still returns an Array of Arrays. 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
Hashes 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", "..."=>"..."}}
Hashes are fundamentally unsorted data structures; Hash#sort is, indeed, what you want. Either that, or sort a list of keys and then use that to enumerate when it's time to output the hash, instead of enumerating directly over the hash using its own methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With