Ruby で特定の値によってマージしながら 2 つのオブジェクトの配列を加算する
概要
私は Ruby On Rails を使用していて、それぞれがオブジェクトの配列を返す 2 つの SQL クエリがあります。これら 2 つの SQL クエリは 2 つの別個の DB からのものであるため、異なるフィールドがありますが、結果を 1 つのリストにマージする必要があります。以下に 2 つの SQL クエリの例と、最終結果がどのようになるかを示します。
SQL1 result == [{id1: 1, name: john, role: user},{id1: 2, name: matt, role: admin}]
SQL2 result == [{id2: 4, externalName: john},{id2: 8, externalName: ronald}]
name == externalName のオブジェクトを 1 つのオブジェクトに結合し、残りはそのままにしておく必要があります。
RESULT == [{id1: 1, name: john, role: user, id2: 4},{id1: 2, name: matt, role: admin},{id2: 8, externalName: ronald}]
基本的に、両方のリストを一緒に追加したいのですが、2 番目のリストの :externalName が最初のリストの :name 値と等しい場合、またはその逆の場合、これら 2 つの別々のオブジェクトが考慮されるため、これら 2 つの別々のオブジェクトを 1 つに結合したいと考えています。 「重複」。 2 つのオブジェクトを組み合わせた結果は、{:id1, :name, :role, :id2} のようになります。これを満たさない残りのオブジェクトは、結果の配列内に表示されます。
両方の配列を素敵な配列に追加する concat を実行しましたが、name == externalName ではマージされません。 .merge() を使用することを考えましたが、オブジェクトの 2 つの配列全体でこれを行う方法と、マージ条件が満たされなかった場合に何が起こるか、結果のリストにそれらが引き続き表示されるかがわかりません。マップについても考えましたが、結果のオブジェクトを他のオブジェクトにマージした後にそれを削除する方法を理解する必要があります。現時点では何が最善のアプローチであるかわかりませんが、いくつかのヒントを探しています。
解決策
これは次のように実行できます。
sql1 = [{id1: 1, name: 'john', role: 'user'},{id1: 2, name: 'matt', role: 'admin'}]
sql2 = [{id2: 4, externalName: 'john'},{id2: 8, externalName: 'ronald'}]
[*sql1,*sql2]
.group_by { |h| h[:name] || h[:externalName] }
.flat_map do |k,v|
v.reduce(&:merge).tap { |h| h.delete(:externalName) if h.key?(:name) }
end
#=> => [{:id1=>1, :name=>"john", :role=>"user", :id2=>4}, {:id1=>2, :name=>"matt", :role=>"admin"}, {:id1=>17, :role=>"user"}, {:id2=>8, :externalName=>"ronald"}]
手順:
アップデート どうやら name は必須キーではないため、マージリダクションがオプションではない、nil 値の大きなグループが生成されます。 nil グループ化を処理するようにコードを更新しました。
sql1 = [{id1: 1, name: 'john', role: 'user'},{id1: 2, name: 'matt', role: 'admin'}, {id1: 17, role: 'user'}, {id1: 12, role: 'admin'} ]
sql2 = [{id2: 4, externalName: 'john'},{id2: 8, externalName: 'ronald'}, {id2: 42}]
[*sql1,*sql2]
.group_by { |h| h[:name] || h[:externalName] }
.flat_map do |k,v|
next v unless k
v.reduce(&:merge).tap { |h| h.delete(:externalName) if h.key?(:name) }
end
#=> [{:id1=>1, :name=>"john", :role=>"user", :id2=>4}, {:id1=>2, :name=>"matt", :role=>"admin"}, {:id1=>17, :role=>"user"}, {:id1=>12, :role=>"admin"}, {:id2=>42}, {:id2=>8, :externalName=>"ronald"}]
その他の仮定
これらは投稿に基づいた仮定です。