简体   繁体   中英

Sorting Hash of Hashes by value (and return the hash, not an array)

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, 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", "..."=>"..."}}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM