Sandra Cieseck
Sandra Cieseck

Reputation: 331

Sort items in a nested hash by their key

I have a nested hash with unsorted keys:

given =  {
  "lorem" => {
     :AA => "foo",
     :GR => "foo",
     :BB => "foo"
  },
  "ipsum" => {
    :ZZ => "foo",
    :GR => "foo",
  }
}

What I'm trying to accomplish is a hash with sorted keys:

goal =  {
  "ipsum" => {
    :GR => "foo",
    :ZZ => "foo"
  },
  "lorem" => {
     :AA => "foo",
     :BB => "foo",
     :GR => "foo"
  }
}

I have experimented with .each method and sort_by

given.each { |topic| topic[:key].sort_by { |k, v| k } }

But I'm getting an error message: TypeError: no implicit conversion of Symbol into Integer

Any help is greatly appreciated!

PS: I noticed with gem pry the output is already sorted. But in IRB it's not.

Upvotes: 1

Views: 1111

Answers (2)

Sebastián Palma
Sebastián Palma

Reputation: 33420

You can use group_by, and transform_values to transform the values inside each hash, also using sort_by plus to_h:

given.transform_values { |value| value.sort.to_h }.sort.to_h

# {"ipsum"=>{:GR=>"foo", :ZZ=>"foo"}, "lorem"=>{:AA=>"foo", :BB=>"foo", :GR=>"foo"}}

You're getting an error because when iterating over a hash, you have to local variables within the block scope to use, the key and its value, you're assigning only one (topic) and trying to get its key, which would be trying to access a key in:

["lorem", {:AA=>"foo", :GR=>"foo", :BB=>"foo"}]

Which isn't possible as is an array. You can update your code to:

given.each do |topic, value|
  ...
end

But anyway you'll need a way to store the changes or updated and sorted version of that topic values.

Upvotes: 4

Anand
Anand

Reputation: 6531

given_hash =  {"lorem"=>{:AA=>"foo", :GR=>"foo", :BB=>"foo"}, "ipsum"=>{:ZZ=>"foo", :GR=>"foo"}} 

Get keys

given_hash.keys
=> ["lorem", "ipsum"]

New sorted hash

new_hash = {}
given_hash.keys.sort.each do |sorted_key|
  new_hash[sorted_key] = given[sorted_key]
end

 => {"ipsum"=>{:ZZ=>"foo", :GR=>"foo"}, "lorem"=>{:AA=>"foo", :GR=>"foo", :BB=>"foo"}} 

There can be a better way to do this.

Upvotes: 0

Related Questions