rj487
rj487

Reputation: 4634

Rails combine two array with hash structure

I got two array which seems similar, part of them are duplicate, and I need to combine them.

Here is the first array.

first

[
      {
             :group_id => "12873",
        :question_sets => [
             {
                  :id => 29435,
                :name => "Question1"
            },
             {
                  :id => 29349,
                :name => "Question2"
            },
            ]
      },
        {
             :group_id => "12876",
        :question_sets => [
             {
                  :id => 29443,
                :name => "Question3"
            }
            ]
      }
]

Here is second array

[
      {
             :group_id => "12873",
        :question_sets => [
             {
                  :id => 29435,
                :name => "Question1"
            },
             {
                  :id => 29338,
                :name => "Question4"
            },
            ]
      },
        {
             :group_id => "12888", #(not in first array)
        :question_sets => [
             {
                  :id => 29443,
                :name => "Question3"
            }
            ]
      }
]

The idea was to combine the question_sets's id and name by the same group_id, every record in second array need to be combined. If there is no the same group_id, create the group_id.

The result will be like

[
      {
             :group_id => "12873",
        :question_sets => [
             {
                  :id => 29435,
                :name => "Question1"
            },
             {
                  :id => 29349,
                :name => "Question2"
            },
             {
                  :id => 29338,
                :name => "Question4"
            }
            ]
      },
        {
             :group_id => "12876",
        :question_sets => [
             {
                  :id => 29443,
                :name => "Question3"
            }
            ]
      },
      {
             :group_id => "12888",
        :question_sets => [
             {
                  :id => 29443,
                :name => "Question3"
            }
            ]
      }
]

Upvotes: 0

Views: 85

Answers (1)

Cary Swoveland
Cary Swoveland

Reputation: 110645

If h1 and h2 are hashes with keys :id and :name, I've assumed that h1[:name] == h2[:name] if and only if h1[:id] == h2[:id]

If a1 and a2 equal your two arrays, you could do the following.

(a1+a2).group_by { |h| h[:group_id] }.
        map { |k,v| { group_id: k,
                      question_sets: v.flat_map { |g| g[:question_sets] }.uniq } }
  #=> [{:group_id=>"12873",
  #     :question_sets=>[
  #       {:id=>29435, :name=>"Question1"},
  #       {:id=>29349, :name=>"Question2"},
  #       {:id=>29338, :name=>"Question4"}
  #      ]
  #    },
  #    {:group_id=>"12876",
  #     :question_sets=>[{:id=>29443, :name=>"Question3"}]
  #    },
  #    {:group_id=>"12888",
  #     :question_sets=>[{:id=>29443, :name=>"Question3"}]
  #    }
  #   ] 

The steps are as follows.

a = a1+a2
  #=> [{:group_id=>"12873",
  #     :question_sets=>[
  #       {:id=>29435, :name=>"Question1"},
  #       {:id=>29349, :name=>"Question2"}
  #     ]
  #    },
  #    {:group_id=>"12876",
  #     :question_sets=>[{:id=>29443, :name=>"Question3"}]
  #    },
  #    {:group_id=>"12873",
  #     :question_sets=>[
  #       {:id=>29435, :name=>"Question1"},
  #       {:id=>29338, :name=>"Question4"}
  #     ]
  #    },
  #    {:group_id=>"12888",
  #     :question_sets=>[{:id=>29443, :name=>"Question3"}]
  #    }
  #   ]

b = a.group_by { |h| h[:group_id] }
  #=> {"12873"=>[
  #     {:group_id=>"12873",
  #      :question_sets=>[
  #        {:id=>29435, :name=>"Question1"},
  #        {:id=>29349, :name=>"Question2"}
  #      ]
  #     },
  #     {:group_id=>"12873",
  #      :question_sets=>[
  #        {:id=>29435, :name=>"Question1"},
  #        {:id=>29338, :name=>"Question4"}
  #      ]
  #     }
  #    ],
  #    "12876"=>[
  #      {:group_id=>"12876",
  #       :question_sets=>[{:id=>29443, :name=>"Question3"}]
  #      }
  #    ],
  #    "12888"=>[
  #      {:group_id=>"12888",
  #       :question_sets=>[{:id=>29443, :name=>"Question3"}]
  #      }
  #    ]
  #   }

b.map { |k,v| { group_id: k,
                question_sets: v.flat_map { |g| g[:question_sets] }.uniq } }
  #=> array of hashes shown above.

Consider the first element of b passed to map's block, to which the block variables are assigned:

k,v = b.first   
k #=> "12873",
v #=> [{:group_id=>"12873",
  #     :question_sets=>[
  #       {:id=>29435, :name=>"Question1"},
  #       {:id=>29349, :name=>"Question2"}
  #     ]
  #    },
  #    {:group_id=>"12873",
  #     :question_sets=>[
  #       {:id=>29435, :name=>"Question1"},
  #       {:id=>29338, :name=>"Question4"}
  #     ] 
  #    }
  #   ]

so the block calculation, which constructs a hash, is as follows.

c = v.flat_map { |g| g[:question_sets] }
  #=> [{:id=>29435, :name=>"Question1"},
  #    {:id=>29349, :name=>"Question2"},
  #    {:id=>29435, :name=>"Question1"},
  #    {:id=>29338, :name=>"Question4"}]
d = c.uniq
  #=> [{:id=>29435, :name=>"Question1"},
  #    {:id=>29349, :name=>"Question2"},
  #    {:id=>29338, :name=>"Question4"}]

so the block returns the hash

{ group_id: k, question_sets: d }
  #=> { group_id: "12873",
  #     question_sets: [
  #       {:id=>29435, :name=>"Question1"},
  #       {:id=>29349, :name=>"Question2"},
  #       {:id=>29338, :name=>"Question4"}
  #     ]
  #   }

The remaining calculations are similar.

Upvotes: 1

Related Questions