Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to sort multidimensional hashes by child hash values?

Tags:

ruby

hash

Is is possible to sort parent hashes by values of children keys?

For example:

{
    :a => 
        {:order => 3},
    :b =>
        {:order => 1},
    :c =>
        {:order => 2}
}

resorted as

{
    :b => 
        {:order => 1},
    :c =>
        {:order => 2},
    :a =>
        {:order => 3}
}
like image 997
nipponese Avatar asked Jan 03 '23 17:01

nipponese


2 Answers

You can convert it to an array of pairs, use sort_by method to target the value you want to sort by, and then convert it back to a hash:

h = {
    :a => 
        {:order => 3},
    :b =>
        {:order => 1},
    :c =>
        {:order => 2}
}

h.sort_by {|k,v| v[:order]}.to_h
=> {:b=>{:order=>1}, :c=>{:order=>2}, :a=>{:order=>3}} 
like image 136
Dan Kreiger Avatar answered Feb 02 '23 00:02

Dan Kreiger


Keep in mind that the only order that a Ruby hash can have is based on insertion order. You need to create a new hash (no sort!) and create the new hash element by element in the order you wish it to have.

Given:

> hash
=> {:a=>{:order=>3}, :b=>{:order=>1}, :c=>{:order=>2}}

You can use .sort_by to do:

> hash.sort_by {|k, h| h[:order]}.to_h
=> {:b=>{:order=>1}, :c=>{:order=>2}, :a=>{:order=>3}}

You can also use the more classic .sort with the spaceship <=> by unpacking the arguments associated with the usual a,b:

> hash.sort {|(a,ha),(b,hb)| ha[:order] <=> hb[:order] }.to_h
=> {:b=>{:order=>1}, :c=>{:order=>2}, :a=>{:order=>3}}

In either case, the .to_h method creates a new hash based on the sorted key, value pairs from the source hash.

Best

like image 23
dawg Avatar answered Feb 02 '23 01:02

dawg