How to Sort a Ruby Hash Alphabetically by Keys

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 Arrays, 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 Strings and Symbols 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.

ruby sort hashes within array in alphabetical order

names_array.sort_by { |hash| hash[:name] }
#=> [{:name=>"item1", :ID=>"127"}, {:name=>"item2", :ID=>"298"}, {:name=>"item3", :ID=>"345"}]

See Enumerable#sort_by

How to preserve alphabetical order of keys when sorting a hash by the value

In many languages, Hashes/Dicts aren't ordered, because of how the are implemented under the covers. Ruby 1.9+ is nice enough to guarantee ordering.

You can do this in a single pass - Ruby allows you to sort by arbitrary criteria.

# Given
pets_ages = {"Eric" => 6, "Harry" => 3, "Georgie" => 12, "Bogart" => 4, "Poly" => 4, "Annie" => 1, "Dot" => 3}

# Sort pets by the critera of "If names are equal, sort by name, else, sort by age"
pets_ages.sort {|(n1, a1), (n2, a2)| a1 == a2 ? n1 <=> n2 : a1 <=> a2 }.to_h

# => {"Annie"=>1, "Dot"=>3, "Harry"=>3, "Bogart"=>4, "Poly"=>4, "Eric"=>6, "Georgie"=>12}

Hash#sort will return an array of [k, v] pairs, but those k, v pairs can be sorted by any criteria you want in a single pass. Once we have the sorted pairs, we turn it back into a Hash with Array#to_h (Ruby 2.1+), or you can use Hash[sorted_result] in earlier versions, as Beartech points out.

You could get as complex as you want in the sort block; if you're familiar with Javascript sorting, Ruby actually works the same here. The <=> method returns -1, 0, or 1 depending on how the objects compare to each other. #sort just expects one of those return values, which tells it how the two given values relate to each other. You don't even have to use <=> at all if you don't want to - something like this is equivalent to the more compact form:

pets_ages.sort do |a, b|
if a[1] == b[1]
if a[0] > b[0]
1
elsif a[0] < b[0]
-1
else
0
end
else
if a[1] > b[1]
1
elsif a[1] < b[1]
-1
end
end
end

As you can see, as long as you always return something in the set (-1 0 1), your sort function can do whatever you want, so you can compose them however you'd like. However, such verbose forms are practically never necessary in Ruby, because of the super handy <=> operator!

As Stefan points out, though, you have a BIG shortcut here: Array#<=> is nice enough to compare each entry between the compared arrays. This means that we can do something like:

pets_ages.sort {|a, b| a.reverse <=> b.reverse }.to_h

This takes each [k, v] pair, reverses it into [v, k], and uses Array#<=> to compare it. Since you need to perform this same operation on each [k, v] pair compared, you can shortcut it even further with #sort_by

pets_ages.sort_by {|k, v| [v, k] }.to_h

What this does is for each hash entry, it passes the key and value to the block, and the return result of the block is what is used to compare this [k, v] pair to other entries. Since comparing [v, k] to another [v, k] pair will give us the result we want, we just return an array consisting of [v, k], which sort_by collects and sorts the original [k, v] pairs by.

How to sort hashes in an array by keys?

array.sort_by {|a| a.is_a?(Hash) ? a.keys.first : a }

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.

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



Leave a reply



Submit