How to sort a Ruby Hash by number value?
No idea how you got your results, since it would not sort by string value... You should reverse a1
and a2
in your example
Best way in any case (as per Mladen) is:
metrics = {"sitea.com" => 745, "siteb.com" => 9, "sitec.com" => 10 }
metrics.sort_by {|_key, value| value}
# ==> [["siteb.com", 9], ["sitec.com", 10], ["sitea.com", 745]]
If you need a hash as a result, you can use to_h
(in Ruby 2.0+)metrics.sort_by {|_key, value| value}.to_h
# ==> {"siteb.com" => 9, "sitec.com" => 10, "sitea.com", 745}
Sorting a hash in ruby based on value and then key
h.sort_by {|k, v| [v, k] }
This uses the fact that Array
mixes in Comparable
and defines <=>
element-wise.Note that the above is equivalent to
h.sort_by {|el| el.reverse }
which is equivalent toh.sort_by(&:reverse)
which may or may not be more readable.If you know that Hash
es usually sort by key first, then by value, the above should be obvious. Maybe with a small comment:
h.sort_by(&:reverse) # sort by value first, then by key
Note: if you simply want to delegate to some property's
<=>
method, (i.e. sort by a key rather than a general comparison function) it is generally prefered to use sort_by
instead of sort
. It's much easier to read. Generally, it also happens to be faster, but the readability aspect is the more important one.You should really only write your own comparison function if absolutely necessary.
So, your non-working example would better be written as
h.sort_by {|el| el[1] }
Personally, I prefer to use destructuring bind in the block parameter list, instead of using el[0]
and el[1]
:h.sort_by {|key, value| value }
However, in this particular case, el[1]
also happens to be identical to el.last
, so that you could simply writeh.sort_by(&:last)
How to sort hash keys by their value in ruby 2.3.0
You can't change the order of a hash, but you can sort the array before turning it into a hash:
data = [
['Frank', 33],
['Stacy', 15],
['Juan', 24],
['Dom', 32],
['Steve', 24],
['Jill', 24]
]
hash = data.sort_by(&:last).to_h
# => { "Stacy" => 15,
# "Juan" => 24,
# "Steve" => 24,
# "Jill" => 24,
# "Dom" => 32,
# "Frank" => 33 }
If you already have a hash, then you'll have to turn it into an array, then sort it, and then turn it back into a hash, e.g. hash.to_a.sort_by(&:last).to_h
. Sorting a hash in Ruby by its value first then its key
Try this:
Assuming:
a = {
'the' => '6',
'we' => '7',
'those' => '5',
'have' => '3',
'hav' => '3',
'haven' => '3'
}
then after doing this:b = a.sort_by { |x, y| [ -Integer(y), x ] }
b
will look like this:[
["we", "7"],
["the", "6"],
["those", "5"],
["hav", "3"],
["have", "3"],
["haven", "3"]
]
Edited to sort by reverse frequencies. How to sort a hash by the values of another array in Ruby?
You don't need to sort anything, and you also don't need to create a lookup table. Your array is already sorted the way you want and your sort_me
hash is already a lookup table:
elements = ['one', 'two', 'three']
# => ["one", "two", "three"]
sort_me = {'three' => 3, 'two' => 2, 'one' => 1}
# => {"three"=>3, "two"=>2, "one"=>1}
elements.map{|key| [key, sort_me[key] ] }.to_h
# => {"one"=>1, "two"=>2, "three"=>3}
If you want to use symbols and strings:elements = ['one', 'two', 'three']
# => ["one", "two", "three"]
sort_me = {three: 3, two: 2, one: 1}
# => {:three=>3, :two=>2, :one=>1}
elements.map{|key| [key.to_sym, sort_me[key.to_sym] ] }.to_h
# => {:one=>1, :two=>2, :three=>3}
Finally, if some elements
are not used in the hash, you could simply remove pairs with nil
values:elements = ['one', 'two', 'two_and_a_half', 'three']
# => ["one", "two", "two_and_a_half", "three"]
elements.map{|key| [key.to_sym, sort_me[key.to_sym] ] }.to_h
# => {:one=>1, :two=>2, :two_and_a_half=>nil, :three=>3}
elements.map{|key| [key.to_sym, sort_me[key.to_sym] ] }.reject{|k, v| v.nil? }.to_h
# => {:one=>1, :two=>2, :three=>3}
Sort a hash by value in descending order and then key in ascending order ruby
In a comparison, arrays get evaluated first by their first elements, then by their second, etc. You can use this fact to enumerate sequential comparisons. Comparing by [-v, k]
first sorts by value (in reverse order) then by key.
>> trial_hash.sort_by{|k, v| [-v, k]}
=> [["key1", 1000], ["key3", 500], ["key4", 500], ["key5", 500], ["key6", 500], ["key2", 34]]
Sorting a hash by value then by key (but the key is reversed)
Use sort:
total = {"Bob"=>37, "Alice"=>42, "Carl"=>42}
total.sort { |(k1, v1), (k2, v2)| [v1, k2] <=> [v2, k1] }.to_h
# => {"Bob"=>37, "Carl"=>42, "Alice"=>42}
First, sort by values (v1 <=> v2
) and then reverse sort by keys (k2 <=> k1
), and since we need it simultaneously, put it into array.EDIT: @Mirror318, it just looks scary, take a look at the excellent explanation here: What is the Ruby <=> (spaceship) operator?
How to sort a Ruby Hash alphabetically by keys
Assuming you want the output to be a hash which will iterate through keys in sorted order, then you are nearly there. Hash#sort_by
returns an Array
of Array
s, and the inner arrays are all two elements.
Ruby's Hash
has a constructor that can consume this output.
Try this:
temp = Hash[ temp.sort_by { |key, val| key } ]
or more conciselytemp = temp.sort_by { |key| key }.to_h
If your hash has mixed key types, this will not work (Ruby will not automatically sort between String
s and Symbol
s for instance) and you will get an error message like comparison of Symbol with String failed (ArgumentError). If so, you could alter the above to temp = Hash[ temp.sort_by { |key, val| key.to_s } ]
to work around the issue. However be warned that the keys will still retain their original types which could cause problems with assumptions in later code. Also, most built-in classes support a .to_s
method, so you may get unwanted results from that (such as unexpected sort order for numeric keys, or other unexpected types).You could, in addition, convert the keys to Strings
with something like this:
temp = Hash[ temp.map { |key, val| [key.to_s, val] }.sort ]
. . . although this approach would lose information about the type of the original key making it impossible to refer back to the original data reliably.
Related Topics
Why Should @@Class_Variables Be Avoided in Ruby
Rvm Can No Longer Install 1.8.7-P352 on MAC Os X Mountain Lion
Warning While Installing The Rails Plugin
After_Save Callback to Set The Updated_By Column to The Current_User
How to (Massively) Reduce The Number of SQL Queries in Rails App
How to Create a Custom Sort Method in Ruby
Private Messages with Faye and Rails
Need Help Installing Ruby 2.7.2 on Mac
Best Way to Create a Blog with Static Pages in Ruby
Does Rails Support a Neat Way of Listening to a Udp Socket
Why Can't Net::Ftp Connect to Server
How to Tell a Ruby Method to Expect a Specific Parameter Type
How to Share Code Across Chef Cookbooks in a Chef-Repo
Ruby: Converting a Nested Ruby Hash to an Un-Nested One
I Am Getting This Gem Install Error for Kgio Gem When I Do a Bundle Install