mf370
mf370

Reputation: 331

Change Key Positions in Ruby Hash

I have the following hash:

my_hash = {
  "redis_1"=>{"group"=>"Output", "name"=>"Redis", "parameters"=>{"redis_db"=>2, "redis_password"=>"<password>"}},
  "file_1"=>{"name"=>"File", "group"=>"Output", "parameters"=>{"file"=>"/opt/var/lib/bots/file-output/ctt.txt", "hierarchical_output"=>false}}
}

And I would like to move the key parameters in each inner hash to the first position, something like this:

my_hash = {
  "redis_1"=>{"parameters"=>{"redis_db"=>2, "redis_password"=>"<password>"}, "group"=>"Output", "name"=>"Redis"},
  "file_1"=>{"parameters"=>{"file"=>"/opt/var/lib/bots/file-output/ctt.txt", "hierarchical_output"=>false}, "name"=>"File", "group"=>"Output"}
}

I have the following code:

my_hash.each_pair do |key, value|
  value.sort_by {|k, v| k == "parameters" ? 0 : 1}
end

I'm not getting any errors, but this code doesn't do anything and I'm quite lost on how to reach the output that I want.

Upvotes: 0

Views: 1391

Answers (2)

Eric Duminil
Eric Duminil

Reputation: 54243

Let's debug your code :

my_hash.each_pair do |key, value|
  p value.sort_by {|k, v| k == "parameters" ? 0 : 1}
end

It outputs :

[["parameters", {"redis_db"=>2, "redis_password"=>"<password>"}], ["group", "Output"], ["name", "Redis"]]
[["parameters", {"file"=>"/opt/var/lib/bots/file-output/ctt.txt", "hierarchical_output"=>false}], ["name", "File"], ["group", "Output"]]

It sorts the pairs correctly, but :

  • it returns arrays instead of hashes
  • it doesn't write the result back to the original hash

For the first problem, you could use to_h.

For the second, you could use transform_values!, available in Ruby 2.4.

Here's the working code, which is still very similar to your proposed method :

my_hash.transform_values! do |subhash|
  subhash.sort_by { |k, _| k == 'parameters' ? 0 : 1 }.to_h
end

Upvotes: 1

sawa
sawa

Reputation: 168121

my_hash
.each {|k, v| my_hash[k] = {"parameters" => v.delete("parameters")}.merge(v)}

or

my_hash
.each_value{|v| v.replace({"parameters" => v.delete("parameters")}.merge(v))}

Return value:

{
  "redis_1"=>{"parameters"=>{"redis_db"=>2, "redis_password"=>"<password>"}, "group"=>"Output", "name"=>"Redis"},
  "file_1"=>{"parameters"=>{"file"=>"/opt/var/lib/bots/file-output/ctt.txt", "hierarchical_output"=>false}, "name"=>"File", "group"=>"Output"}
}

Upvotes: 1

Related Questions