user3439613
user3439613

Reputation: 3

Combine duplicate hash keys in ruby

I am attempting to take JSON like this:

{"myhostname"=>
  {"client"=>"exemplar", "tag"=>"mytag"},
 "mysecondhost"=>
  {"client"=>"exemplar", "tag"=>"mytag2"},
 "myhost2"=>
  {"client"=>"exemplar", "envtag"=>"mytag2"}}

My goal is to output something like:

mytag:myhostname
mytag2:mysecondhost, myhost2

It'll need to be JSON at the end of the day, but I'm using pyjojo and that seems to do a good job of reformatting it. I'm trying to get a list of hosts for each key.

The hostnames are dynamic. It's been easy to get an output of "tag:host" for each of these, but I'm having a hard time dealing with the situation where the tag is duplicated, and I need to return each host as a comma separated value.

Thank you in advance.

Upvotes: 0

Views: 892

Answers (1)

Arup Rakshit
Arup Rakshit

Reputation: 118261

To remap key value pairs in a JSON object I think you want something like this:

hash = { 
         "myhostname"=> {"client"=>"exemplar", "tag"=>"mytag"},
         "mysecondhost"=> {"client"=>"exemplar", "tag"=>"mytag2"},
         "myhost2"=>{"client"=>"exemplar", "envtag"=>"mytag2"}
       }

new_hash = Hash[ 
                 hash.map { |k,h| [k,h.values.last] }.group_by(&:last)
                 .map { |k,v| [k,v.map(&:first)] }
               ]
# => {"mytag"=>["myhostname"], "mytag2"=>["mysecondhost", "myhost2"]}

Then iterate through the hash as below:

 new_hash.each { |k,v| puts "k: #{v.join(',')}" }
# >> k: myhostname
# >> k: mysecondhost,myhost2

Explanation:

Look at this #map method.

# collecting hostname and tag key value as an array
hash.map { |k,h| [k,h.values.last] }
# => [["myhostname", "mytag"],
#     ["mysecondhost", "mytag2"],
#     ["myhost2", "mytag2"]]

Look at this #group_by method.

# grouping on the tag key's value as to get a below hash
grouped_hash = hash.map { |k,h| [k,h.values.last] }.group_by(&:last)
# => {"mytag"=>[["myhostname", "mytag"]],
#     "mytag2"=>[["mysecondhost", "mytag2"], ["myhost2", "mytag2"]]}

# from the gropued has based on tag key's value, I would collect the tag name and 
# host names associated with the specific tag.
grouped_hash.map { |k,v| [k,v.map(&:first)] }
# => # => [["mytag", ["myhostname"]], ["mytag2", ["mysecondhost", "myhost2"]]]

Look at this Hash::[] method.

# finally got the desired Hash
Hash[grouped_hash.map { |k,v| [k,v.map(&:first)] }]
# => {"mytag"=>["myhostname"], "mytag2"=>["mysecondhost", "myhost2"]}

Upvotes: 4

Related Questions