Ruby sort by multiple values?

Ruby

Ruby Problem Overview


I have an array of hashes:

a=[{ 'foo'=>0,'bar'=>1 },   { 'foo'=>0,'bar'=>2 },   ... ]

I want to sort the array first by each hash's 'foo', then by 'bar'. Google tells me this is how it's done:

a.sort_by {|h| [ h['foo'],h['bar'] ]}

But this gives me the ArgumentError "comparison of Array with Array failed". What does this mean?

Ruby Solutions


Solution 1 - Ruby

a.sort { |a, b| [a['foo'], a['bar']] <=> [b['foo'], b['bar']] }

Solution 2 - Ruby

It probably means you're missing one of the fields 'foo' or 'bar' in one of your objects.

The comparison is coming down to something like nil <=> 2, which returns nil (instead of -1, 0 or 1) and #sort_by doesn't know how to handle nil.

Try this:

a.sort_by {|h| [ h['foo'].to_i, h['bar'].to_i ]}

Solution 3 - Ruby

What you have posted works in Ruby 1.8.7:

ruby-1.8.7-p302 > a = [{'foo'=>99,'bar'=>1},{'foo'=>0,'bar'=>2}]
 => [{"foo"=>99, "bar"=>1}, {"foo"=>0, "bar"=>2}] 

ruby-1.8.7-p302 > a.sort_by{ |h| [h['foo'],h['bar']] }
 => [{"foo"=>0, "bar"=>2}, {"foo"=>99, "bar"=>1}] 

ruby-1.8.7-p302 > a.sort_by{ |h| [h['bar'],h['foo']] }
 => [{"foo"=>99, "bar"=>1}, {"foo"=>0, "bar"=>2}] 

Solution 4 - Ruby

This exception occurs when the result array used for the comparison contains both nil and non-nil values.

Solution 5 - Ruby

This error appeares when you have unstable keys and trying to sort by them. Example:

[{'foo'=>99,'bar'=>1},{'foo'=>0,'bar'=>2, 'qwe' => 7}]
a.sort_by{|v| v['qwe']}
ArgumentError: comparison of NilClass with 7 failed

Try to do

a.sort_by{|v| [v['qwe']].select{|k| not k.nil?}}

But it doesnt work for me in

[v['index'],v['count'],v['digit'],v['value']]

where digit is unstable

Solution 6 - Ruby

> comparison of Array with Array failed

This means (at least in my case) that the types of array elements are different. When I made sure all array items are of the same time (Integer, for example), sorting started to work.

Solution 7 - Ruby

consider compacting the array (removing nil entries), and as a bonus, if it's string comparision, downcase the values for case insensitive sorting.

a.compact.sort_by { |h| [h['foo'].downcase, h['bar'].downcase] }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionherpderpView Question on Stackoverflow
Solution 1 - Rubydj2View Answer on Stackoverflow
Solution 2 - RubyWill MaddenView Answer on Stackoverflow
Solution 3 - RubyPhrogzView Answer on Stackoverflow
Solution 4 - RubyWeston GangerView Answer on Stackoverflow
Solution 5 - Rubyuser3713526View Answer on Stackoverflow
Solution 6 - Rubyyegor256View Answer on Stackoverflow
Solution 7 - RubyVinnyQ77View Answer on Stackoverflow