Reputation: 16216
Would this be the best way to sort a hash and return Hash object (instead of Array):
h = {"a"=>1, "c"=>3, "b"=>2, "d"=>4}
# => {"a"=>1, "c"=>3, "b"=>2, "d"=>4}
Hash[h.sort]
# => {"a"=>1, "b"=>2, "c"=>3, "d"=>4}
Upvotes: 307
Views: 234717
Reputation: 1797
You can use sort
method and then convert array back to hash with to_h
method
h = { "a" => 1, "c" => 3, "b" => 2, "d" => 4 }
h.sort.to_h
# => { "a" => 1, "b" => 2, "c" => 3, "d" => 4 }
Upvotes: 2
Reputation: 2004
I borrowed Boris Stitnicky's inspired solution to patch an in-place sort!
method into Hash
:
def sort!
keys.sort!.each { |k| store k, delete(k) }
self
end
Upvotes: -1
Reputation: 4137
Sort hash by key, return hash in Ruby
With destructuring and Hash#sort
hash.sort { |(ak, _), (bk, _)| ak <=> bk }.to_h
Enumerable#sort_by
hash.sort_by { |k, v| k }.to_h
Hash#sort with default behaviour
h = { "b" => 2, "c" => 1, "a" => 3 }
h.sort # e.g. ["a", 20] <=> ["b", 30]
hash.sort.to_h #=> { "a" => 3, "b" => 2, "c" => 1 }
Note: < Ruby 2.1
array = [["key", "value"]]
hash = Hash[array]
hash #=> {"key"=>"value"}
Note: > Ruby 2.1
[["key", "value"]].to_h #=> {"key"=>"value"}
Upvotes: 20
Reputation: 2391
I had the same problem ( I had to sort my equipments by their name ) and i solved like this:
<% @equipments.sort.each do |name, quantity| %>
...
<% end %>
@equipments is a hash that I build on my model and return on my controller. If you call .sort it will sort the hash based on it's key value.
Upvotes: -1
Reputation: 1916
ActiveSupport::OrderedHash is another option if you don't want to use ruby 1.9.2 or roll your own workarounds.
Upvotes: 6
Reputation: 39695
I've always used sort_by
. You need to wrap the #sort_by
output with Hash[]
to make it output a hash, otherwise it outputs an array of arrays. Alternatively, to accomplish this you can run the #to_h
method on the array of tuples to convert them to a k=>v
structure (hash).
hsh ={"a" => 1000, "b" => 10, "c" => 200000}
Hash[hsh.sort_by{|k,v| v}] #or hsh.sort_by{|k,v| v}.to_h
There is a similar question in "How to sort a Ruby Hash by number value?".
Upvotes: 73
Reputation: 132157
Note: Ruby >= 1.9.2 has an order-preserving hash: the order keys are inserted will be the order they are enumerated. The below applies to older versions or to backward-compatible code.
There is no concept of a sorted hash. So no, what you're doing isn't right.
If you want it sorted for display, return a string:
"{" + h.sort.map{|k,v| "#{k.inspect}=>#{v.inspect}"}.join(", ") + "}"
or, if you want the keys in order:
h.keys.sort
or, if you want to access the elements in order:
h.sort.map do |key,value|
# keys will arrive in order to this block, with their associated value.
end
but in summary, it makes no sense to talk about a sorted hash. From the docs, "The order in which you traverse a hash by either key or value may seem arbitrary, and will generally not be in the insertion order." So inserting keys in a specific order into the hash won't help.
Upvotes: 86
Reputation: 212
@ordered = {}
@unordered.keys.sort.each do |key|
@ordered[key] = @unordered[key]
end
Upvotes: 0
Reputation: 83680
No, it is not (Ruby 1.9.x)
require 'benchmark'
h = {"a"=>1, "c"=>3, "b"=>2, "d"=>4}
many = 100_000
Benchmark.bm do |b|
GC.start
b.report("hash sort") do
many.times do
Hash[h.sort]
end
end
GC.start
b.report("keys sort") do
many.times do
nh = {}
h.keys.sort.each do |k|
nh[k] = h[k]
end
end
end
end
user system total real
hash sort 0.400000 0.000000 0.400000 ( 0.405588)
keys sort 0.250000 0.010000 0.260000 ( 0.260303)
For big hashes difference will grow up to 10x and more
Upvotes: 14
Reputation: 12578
You gave the best answer to yourself in the OP: Hash[h.sort]
If you crave for more possibilities, here is in-place modification of the original hash to make it sorted:
h.keys.sort.each { |k| h[k] = h.delete k }
Upvotes: 16
Reputation: 1000
I liked the solution in the earlier post.
I made a mini-class, called it class AlphabeticalHash
. It also has a method called ap
, which accepts one argument, a Hash
, as input: ap variable
. Akin to pp (pp variable
)
But it will (try and) print in alphabetical list (its keys). Dunno if anyone else wants to use this, it's available as a gem, you can install it as such: gem install alphabetical_hash
For me, this is simple enough. If others need more functionality, let me know, I'll include it into the gem.
EDIT: Credit goes to Peter, who gave me the idea. :)
Upvotes: -2