How to sort a hash within a hash?
Use Hash#transform_values
to sort values:
hash.transform_values { |v| v.sort.to_h }
#⇒ {2012=>{"post_season"=>[:game_4, :game_5],
# "regularseason"=>[:game_1, :game_2, :game_3]},
# 2013=>{"post_season"=>[:game_9, :game_10],
# "regularseason"=>[:game_6, :game_7, :game_8]},
# 2014=>{"post_season"=>[:game_11, :game_12, :game_13],
# "regularseason"=>[:game_14, :game_15]}}
Sort hash by key which is a string
Suppose you started with
str = "27,2,2,2,41,26,26,26,48,48,41,6,11,1,41"
and created the following hash
h = str.split(',').inject(Hash.new(0)) { |h, e| h[e] += 1 ; h }
#=> {"27"=>1, "2"=>3, "41"=>3, "26"=>3, "48"=>2, "6"=>1, "11"=>1, "1"=>1}
I removed compact
because the array str.split(',')
contains only (possibly empty) strings, no nil
s.
Before continuing, you may want to change this last step to
h = str.split(/\s*,\s*/).each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
#=> {"27"=>1, "2"=>3, "41"=>3, "26"=>3, "48"=>2, "6"=>1, "11"=>1, "1"=>1}
Splitting on the regex allows for the possibility of one or more spaces before or after each comma, and Enumerable#each_with_object avoids the need for that pesky ; h
. (Notice the block variables are reversed.)
Then
h.sort_by { |k,_| k.to_i }.to_h
#=> {"1"=>1, "2"=>3, "6"=>1, "11"=>1, "26"=>3, "27"=>1, "41"=>3, "48"=>2}
creates a new hash that contains h
's key-value pairs sorted by the integer representations of the keys. See Hash#sort_by.
Notice we've created two hashes. Here's a way to do that by modifying h
in place.
h.keys.sort_by(&:to_i).each { |k| h[k] = h.delete(k) }
#=> ["1", "2", "6", "11", "26", "27", "41", "48"] (each always returns the receiver)
h #=> {"1"=>1, "2"=>3, "6"=>1, "11"=>1, "26"=>3, "27"=>1, "41"=>3, "48"=>2}
Lastly, another alternative is to sort str.split(',')
before creating the hash.
str.split(',').sort_by(&:to_i).each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
#=> {"1"=>1, "2"=>3, "6"=>1, "11"=>1, "26"=>3, "27"=>1, "41"=>3, "48"=>2}
Sort Hash Keys based on order of same keys in array
hash = { a: 23, b: 12 }
array = [:b, :a]
array.zip(hash.values_at(*array)).to_h
#=> {:b=>12, :a=>23}
The steps:
v = hash.values_at(*array)
#=> [12, 23]
a = array.zip(v)
#=> [[:b, 12], [[:a, 23]]
a.to_h
#=> {:b=>12, :a=>23}
How can I sort ruby hash with string key by setting priority to the key elements?
If your priority array contains all of the hash keys, you don't need sorting. You can simply take the hash apart and construct a new one.
hash = {
red: { something: ''},
green: { something: '' },
yellow: { something: ''}
}
priority = %i[green yellow red]
hash.slice(*priority)
# => {:green=>{:something=>""}, :yellow=>{:something=>""}, :red=>{:something=>""}}
Sort array of hash by key in descending order in Ruby
You can do
h.sort_by! { |k| -k[:bookings_nd] }
or
h.sort_by! { |k| k[:bookings_nd] }.reverse!
Also i guess this question is duplicate for Sorting an array in descending order in Ruby
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 concisely
temp = 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.
Sort hash by key as a reverse order, return hash in Ruby
Which version of ruby are you using? In 1.8 hashes cannot be ordered, in 1.9 they are ordered based on insertion. Here's more info on that.
Given the variation in how they're handled I wouldn't focus on sorting the hash itself, but on sorting your keys and using them as a reference, something like:
data = {20111104111221=>[4, 5, 6], 20111104111220=>[7, 8, 9], 20111104110950=>[1, 2, 3]}
keys = data.keys.sort.reverse
keys.each do |key|
puts data[key].pretty_inspect
# ... do work ...
end
The debug line is in there just as an example of how to access your values. Hope this helps!
Is there a way of changing the key of a hash via sort / sort_by?
Looks like you're trying to split the hash into keys and values, sort each of those separately, and then put them back together as a hash.
In that case, you could do something like this:
hash.to_a.transpose.map(&:sort).transpose.to_h
Step by step it works like this:
# First array-ify the hash into key/value pairs
hash.to_a
# [[:a, 2], [:b, 5], [:c, 1]]
# Then transpose to group the keys and values together
hash.to_a.transpose
# [[:a, :b, :c], [2, 5, 1]]
# Then sort the keys and values separately
hash.to_a.transpose.map(&:sort)
# [[:a, :b, :c], [1, 2, 5]]
# And transpose again to get key/value pairs
hash.to_a.transpose.map(&:sort).transpose
# [[:a, 1], [:b, 2], [:c, 5]]
# And combine the array of key/value pairs into a hash
hash.to_a.transpose.map(&:sort).transpose.to_h
# {:a=>1, :b=>2, :c=>5}
You could also manually do the hash.to_a.transpose
step like this:
[hash.keys, hash.values].map(&:sort).transpose.to_h
You don't even have to assume that #keys
and #values
will produce arrays in any particular order since you're sorting everything anyway.
Related Topics
Find Out If Current Time Is Between Two Times
To_D to Always Return 2 Decimals Places in Ruby
How to Get the Current Absolute Url in Ruby on Rails
How to Reload the Current Page in Ruby on Rails
Validation for Non-Negative Integers and Decimal Values
What Does the (Unary) * Operator Do in This Ruby Code
Why Doesn't Ruby Support I++ or I-- (Increment/Decrement Operators)
What's the Difference Between Equal, Eql, ===, and ==
Rbenv Not Changing Ruby Version
How to Dynamically Create a Local Variable
Understanding the Rails Authenticity Token
How to Understand Nil Vs. Empty Vs. Blank in Ruby
Difference Between "And" and && in Ruby