Steven Kwok
Steven Kwok

Reputation: 199

How to combines two nested data structures into one?

I need to definite a method that combines two nested data structures into one.

here is the first hash:

[
  {
     "blake" => {
       :awesomeness => 10,
       :height => "74",
       :last_name => "johnson"
     },
      "ashley" => {
        :awesomeness => 9,
        :height => 60,
        :last_name => "dubs"
     }
   }
]

here is the second hash:

[
   {
     :first_name => "blake"
   },
   {
     :first_name => "ashley"
   }
]

the result will be like this:

[
   {
      :first_name => "blake",
      :awesomeness => 10,
      :height => "74",
      :last_name => "johnson"
   },
   {
      :first_name => "ashley",
      :awesomeness => 9,
      :height => 60,
      :last_name => "dubs"
   }
]

Upvotes: 3

Views: 764

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110685

I assume you meant to define the following hash (rather than an array containing one element, a hash).

h = { "blake" =>  { :awesomeness => 10,
                    :height => "74",
                    :last_name => "johnson"
                  },
      "ashley" => { :awesomeness => 9,
                    :height => 60,
                    :last_name => "dubs"
                  }
    }

There are many ways to add the key-value pairs :first_name=>"blake" and :first_ame=>"ashley" to their associated hashes. Here is one:

 f = h.each_with_object({}) { |(k,v),g| g[k] = { :first_name => k }.merge(v) }
   #=> {"blake" =>{:first_name=>"blake",
   #               :awesomeness=>10,
   #               :height=>"74",
   #               :last_name=>"johnson"},
   #    "ashley"=>{:first_ame=>"ashley",
   #               :awesomeness=>9,
   #               :height=>60,
   #               :last_name=>"dubs"}} 

So this begs the question: what is the function of the following array?

a = [{ :first_name => "blake" }, { :first_name => "ashley" }]    

If this array is used to specify which keys of f are to be retained, we could write

retain = a.map { |g| g[:name] } 
  #=> ["blake", "ashley"] 
f.select { |k| retain.include?(k) }
  #=> {"blake"=>{:first_name=>"blake", :awesomeness=>10, :height=>"74",
  #              :last_name=>"johnson"},
  #    "ashley"=>{:first_name=>"ashley", :awesomeness=>9, :height=>60,
  #               :last_name=>"dubs"}} 

On the other hand, if

a = [{:name=>"blake"}]

then

retain = a.map { |g| g[:name] } 
  #=> ["blake"] 
f.select { |k| retain.include?(k) }
  #=> {"blake"=>{:first_name=>"blake", :awesomeness=>10, :height=>"74",
  #              :last_name=>"johnson"}} 

Upvotes: 2

Wand Maker
Wand Maker

Reputation: 18762

Please note that what you call hashes are indeed arrays, and that too they are not consistent. First one is an array containing single hash, and second one is an array containing two hashes.

For the given two arrays, if we call the first v1 and second one v2, then, below code should give the output you desire:

v1[0].values.map.with_index {|v, i| v2[i].merge(v)}

Explanation:

Hash#merge merges two hashes, so it has to be used to achieve the result.

The first hash will be from v1 - we pick the first element of v1 array, which is a hash, and take all its values which are hashes themselves - thus, we have an array of hash in v1[0].values.

The second array of hashes is v2.

Now, we use the Enumerable#map method to iterate over first array of hashes and collecting the result of merging each of its elements with corresponding element from v2.

Upvotes: 4

Related Questions