Sort hash in model

Hi, I have this hash:

hash = { 4049=>[4133, 100], 5814=>[4075, 84], 382543=>[4064, 74], 382544=>[4065, 99], 382545=>[4066, 75] }

I need to sort (DESC) this hash by the second item of array.

Example: 100, 84, 74, 99, 75

How can I solve this problem ? I’m using sort method but can’t work it out.

Thanks.

You can’t really sort a regular hash—by definition a hash is unordered. So what output do you want? Possibly an array structured (I’m not showing it sorted) something like: [[4049,[4133,100]],[5814,[4075,84]]…]. Rails provides a kind of hybrid thing, OrderedHash, which you could build—but you’d have to build an array and then sort it anyway in order to be able to insert items into an OrderedHash in sort order.

Well, assuming that you know a Hash isn't really sortable and you'll end up with an Array (of Arrays)...

irb2.2.2> hash = { 4049=>[4133, 100], 5814=>[4075, 84], 382543=>[4064, 74], 382544=>[4065, 99], 382545=>[4066, 75] } #2.2.2 => {4049=>[4133, 100], 5814=>[4075, 84], 382543=>[4064, 74], 382544=>[4065, 99], 382545=>[4066, 75]} irb2.2.2> hash.sort_by {|k,v| v[1]} #2.2.2 => [[382543, [4064, 74]], [382545, [4066, 75]], [5814, [4075, 84]], [382544, [4065, 99]], [4049, [4133, 100]]] irb2.2.2> hash.sort_by {|k,v| v[1]}.reverse #2.2.2 => [[4049, [4133, 100]], [382544, [4065, 99]], [5814, [4075, 84]], [382545, [4066, 75]], [382543, [4064, 74]]] irb2.2.2> hash.sort_by {|k,v| -v[1]} #2.2.2 => [[4049, [4133, 100]], [382544, [4065, 99]], [5814, [4075, 84]], [382545, [4066, 75]], [382543, [4064, 74]]]

You really want Hash#sort_by

-Rob

sorted_by_second_value = Hash[hash.sort_by { |_, v| v[1] }]

For those saying ruby hashes are unordered: http://ruby-doc.org/core-2.2.2/Hash.html

Hashes enumerate their values in the order that the corresponding keys were inserted.

sorted_by_second_value ​.map { |_, v| v[1] }

=> [74, 75, 84, 99, 100]

​Paul​

Thank you all.

Paul, I end up doing this:

sorted_by_second_value = Hash[hash.sort_by { |_, v| v[1] }]

sorted_by_second_value.to_a.reverse.to_h

Thanks.

Thank you all.

Paul, I end up doing this:

sorted_by_second_value = Hash[hash.sort_by { |_, v| v[1] }] sorted_by_second_value.to_a.reverse.to_h

​Here you're converting an array (​hash.sort_by { |_, v| v[1] }) to a hash ( Hash[...]) then back to an array (.to_a) then reversing and then turning back into a hash (.to_h).

Assuming you don't need the intermediate results, you can skip a couple of those by just doing,

Hash[hash.sort_by { |_, v| v[1] }.reverse]

or,

hash.sort_by { |_, v| v[1] }.reverse.to_h # if you prefer .to_h

There's an interesting stackoverflow analysis on ways of descending order sorts in Ruby. Summary: sort_by + reverse is the fastest, slightly ahead of the -v hack (fewer ops presumably).

Paul