将两个对象数组添加到一起,同时在Ruby中按特定值合并

j7dteeu8  于 2023-11-18  发布在  Ruby
关注(0)|答案(3)|浏览(110)

我正在使用Ruby On Rails,我有两个SQL查询,每个查询都返回一个对象数组。这两个SQL查询来自两个独立的DB,因此它们具有不同的字段,但是,我应该将结果合并到一个列表中。下面是两个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的所有对象合并到一个对象中,但保留其余对象。

RESULT == [{id1: 1, name: john, role: user, id2: 4},{id1: 2, name: matt, role: admin},{id2: 8, externalName: ronald}]


基本上,我想把两个列表加在一起,但是,当第二个列表中的:externalName等于第一个列表中的:name值时,或者反之亦然,我们想把这两个独立的对象合并合并成一个,因为它们会被认为是“重复的”。两个对象的合并结果看起来像这样{:id1, :name, :role, :id2}。其余不满足这个条件的对象仍然会出现在结果数组中。
我已经做了一个concat,它只是把两个数组加在一起成为一个漂亮的数组,但是它不会在name == externalName上合并。我想过使用.merge(),但不确定如何在两个完整的对象数组上做到这一点,以及如果不满足合并条件会发生什么,这些仍然会出现在结果列表中。我也想过一个Map,但然后需要弄清楚如何删除合并后的结果对象。不知道什么是最好的方法是现在,只是寻找一些提示。

m4pnthwp

m4pnthwp1#

您可以按如下方式执行此操作:

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"}]

字符串
步骤:

  • [*sql1,*sql2]-合并合并两个阵列
  • .group_by {|h| h[:name] || h[:externalName]}-如果h[:name]为falsey,则按:name:externalName的值对元素进行分组(在本例中假定为nil
  • map do |_,v|-将根据块的返回值返回一个新的Array,当在Hash上调用时(由group_by返回),它将产生块的键和值。在这种情况下,我们不关心键,所以我们使用_来表示。
  • v.reduce(&:merge)-将值合并为单个Hash
  • tap { |h| h.delete(:externalName) if h.key?(:name) }-tap将结果Hash生成到块中,如果Hashname键,则删除:externalName键。此块将始终返回生成的对象。
    更新显然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"}]

  • 其他假设 *

以下是基于员额的假设:

  • sql1中没有重复的名称,sql2中没有重复的externalNames(导致最多2个组; 1个值来自sql1,1个值来自sql2
  • sql1sql2之间没有重叠的键。否则,结果值将是sql2的值
eanckbw9

eanckbw92#

这个可以

sql1_result = [{id1: 1, name: 'john', role: 'user'},{id1: 2, name: 'matt', role: 'admin'}]
sql2_result = [{id2: 4, externalName: 'john'},{id2: 8, externalName: 'ronald'}]

merged_result = sql1_result.map do |hash1|
  matching_hash2 = sql2_result.find { |hash2| hash2[:externalName] == hash1[:name] }
  matching_hash2 ? hash1.merge(id2: matching_hash2[:id2]) : hash1
end

merged_result += sql2_result.reject { |hash2| merged_result.any? { |hash1| hash1[:id2] == hash2[:id2] } }

puts merged_result

字符串

merged_result = sql1_result.each_with_object([]) do |hash1, result|
  matching_hash2 = sql2_result.find { |hash2| hash2[:externalName] == hash1[:name] }
  if matching_hash2
    result << hash1.merge(id2: matching_hash2[:id2])
    sql2_result.delete(matching_hash2)
  else
    result << hash1
  end
end


结果

{:id1=>1, :name=>"john", :role=>"user", :id2=>4}
{:id1=>2, :name=>"matt", :role=>"admin"}
{:id2=>8, :externalName=>"ronald"}

dddzy1tm

dddzy1tm3#

在阅读了对@engineersmnky的回答的评论后,我发现这个问题已经有所变化。假设sql1sql2如下(摘自@engineersmnky的回答)。

sql1 = [{id1: 1, name: 'john', role: 'user'},
        {id1: 2, name: 'matt', role: 'admin'},
        {id1: 17, role: 'user'},
        {id1: 12, role: 'admin'} ]

个字符
获得所需结果的一种方法如下。

wonames = []

x

h = sql1.each_with_object({}) do |g,h|
  if g.key?(:name)
    h[g[:name]] = g
  else
    wonames << g
  end
end
  #=> {"john"=>{:id1=>1, :name=>"john", :role=>"user"},
  #    "matt"=>{:id1=>2, :name=>"matt", :role=>"admin"}}
sql2.each_with_object(h) do |g,h|
  if g.key?(:externalName)
    name = g[:externalName]
    if h.key?(name)
      h[name][:id2] = g[:id2]
    else
      h.update(name=>g)
    end
  else
    wonames << g
  end
end.values.concat(wonames)
  #=> [
  #     {:id1=>1, :name=>"john", :role=>"user", :id2=>4},
  #     {:id1=>2, :name=>"matt", :role=>"admin"},
  #     {:id2=>8, :externalName=>"ronald"},
  #     {:id1=>17, :role=>"user"},
  #     {:id1=>12, :role=>"admin"},
  #     {:id2=>42}]

的一种或多种

相关问题