0

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"
            }
            ]
      }
]
5
  • 1
    You've set up your requirements, but what did you try to implement them? Commented Aug 15, 2016 at 3:14
  • Cause I got two API, but it return like them, I need to modify them to a be new API. Commented Aug 15, 2016 at 3:39
  • Hi and welcome to Stack Overflow. Here we expect you to have a go yourself first, then if you come across a problem, show us what you tried (even if it's not working) and any error message you received, and we will help you debug what happened. We wont' write or design your code for you - you have to give it a bash yourself. You might surprise yourself at how much you can do once you just give it a shot :) Commented Aug 15, 2016 at 4:39
  • Thanks, I got that, I will update my question. Commented Aug 15, 2016 at 5:43
  • 1
    Your example is very helpful. In future, I suggest that you assign a variable to each input object (e.g., arr1 = [ { :group_id => "12873",...). That way, readers can refer to those variables in answers and comments without having to define them (and they will all use the same variable names, which is convenient for running code). One thing that was not clear about your question prompted me to make an assumption that is given in the first line of my answer. You might want to clarify that with an edit. Commented Aug 15, 2016 at 7:59

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

You are such a genius, I was supposed to put many each do to check every key value exist or not. Ruby is really a astonishing language!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.