Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting a hash in ruby based on value and then key

Tags:

sorting

ruby

How do you sort a hash in ruby based on the value and then key? For example

h = {4 => 5, 2 => 5, 7 => 1}

would sort into

[[7, 1], [2,5], [4, 5]]

I can sort based on the value by doing

h.sort {|x,y| x[1] <=> y[1]}

but I can't figure out how to sort based on value and then key if the values are the same

like image 668
Ben Avatar asked Dec 13 '10 02:12

Ben


People also ask

How do you sort a hash based on values in Ruby?

##Hash#keys and Hash#values A simple way to sort a hash keys or values is to use the methods Hash#keys and Hash#values. Those 2 methods are simply returning an array of the keys or the values of your hash. So as soon as you get an array with only one of the type of values you want to work with, it's all good!

How do I sort a hash key in Ruby?

If you want to access a Hash in a sorted manner by key, you need to use an Array as an indexing mechanism as is shown above. This works by using the Emmuerator#sort_by method that is mixed into the Array of keys. #sort_by looks at the value my_hash[key] returns to determine the sorting order.

How do you sort hash alphabetically in Ruby?

To sort a hash in Ruby without using custom algorithms, we will use two sorting methods: the sort and sort_by. Using the built-in methods, we can sort the values in a hash by various parameters.


1 Answers

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 to

h.sort_by(&:reverse)

which may or may not be more readable.

If you know that Hashes 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 write

h.sort_by(&:last)
like image 189
Jörg W Mittag Avatar answered Nov 15 '22 23:11

Jörg W Mittag