Reputation: 358
I have the following array of hashes:
arr = [{:id=>1, :val=>30}, {:id=>2, :val=>30}, {:id=>1002, :val=>82}]
I need to:
:val
, and:val
value is ascending or descendinglike this:
arr.sort_by_ascending_order.map{|x| x[:id]}
# => [1, 2, 1002]
arr.sort_by_descending_order.map{|x| x[:id]}
# => [1002, 2, 1]
I cannot guarantee the second condition. For example,
arr.sort{|x,y| x[:val] <=> y[:val]}.map{|x| x[:id]}
# => [1, 2, 1002]
arr.sort{|x,y| y[:val] <=> x[:val]}.map{|x| x[:id]}
# => [1002, 1, 2]
Does anybody know how to fix it?
Upvotes: 0
Views: 677
Reputation: 114178
You can provide an array:
arr = [{:id=>1, :val=>30}, {:id=>2, :val=>30}, {:id=>1002, :val=>82}]
arr.sort { |x, y| [x[:val], x[:id]] <=> [y[:val], y[:id]] }
#=> [{:id=>1, :val=>30}, {:id=>2, :val=>30}, {:id=>1002, :val=>82}]
arr.sort { |x, y| [y[:val], y[:id]] <=> [x[:val], x[:id]] }
#=> [{:id=>1002, :val=>82}, {:id=>2, :val=>30}, {:id=>1, :val=>30}]
This will sort by :val
first and then by :id
(see Array#<=>
for details).
You could also use sort_by
:
arr.sort_by { |h| [h[:val], h[:id]] }
#=> [{:id=>1, :val=>30}, {:id=>2, :val=>30}, {:id=>1002, :val=>82}]
Update:
Of course, this is not limited to hash values. You could use the element's index (as suggested by sawa) as a secondary sort condition to achieve a stable sort:
arr.sort_by.with_index { |h, i| [h[:val], i] }
#=> [{:id=>1, :val=>30}, {:id=>2, :val=>30}, {:id=>1002, :val=>82}]
Upvotes: 4