Ruby在2个哈希数组上循环并比较键值

Ruby在2个哈希数组上循环并比较键值,ruby,Ruby,我在尝试循环两个哈希数组时遇到问题。 我的哈希值如下所示: h1= [ {"name"=>"postgresql", "version"=>29}, {"name"=>"java", "version"=>8}, {"name"=>"python", "version"=>

我在尝试循环两个哈希数组时遇到问题。 我的哈希值如下所示:

h1= [
  {"name"=>"postgresql", "version"=>29},
  {"name"=>"java", "version"=>8},
  {"name"=>"python", "version"=>3}
]

h2= [
  {"name"=>"postgresql", "release"=>"postgresql-release", "url"=>"https://github.com/repo/postgresql-release"},
  {"name"=>"java", "release"=>"java-release", "url"=>"https://github.com/repo/java-release"}
]

combined = []
在检查h1和h2中“name”字段的散列值后,我需要将这两个散列组合在一个名为
combined
的数组中,以便:

  • 如果
    h1[“name”]==h2[“name”]
    -->保存名称、版本、版本和url
  • 如果
    h1[“name”]!=h2[“name”]
    (例如:python在h1中找到,但在h2中找不到)--->保存名称、版本、版本=nil、url=nil
组合的
数组应如下所示:

combined = [
  {"name"=>"postgresql", "version"=>29, "release"=>"postgresql-release", "url"=>"https://github.com/repo/postgresql-release"},
  {"name"=>"java", "version"=>8, "release"=>"java-release", "url"=>"https://github.com/repo/java-release"},
  {"name"=> "python", "version"=>3, "release"=> nil, "url"=> nil}
]
# ... as before
defaults = {'url' => nil, 'version' => nil}
combined_hash = combined_hash.transform_values { |v| defaults.merge(v) }
combined = combined_hash.values
我已经尝试了很多,并且总是有更多的迭代和/或不能在不同名称的情况下打印任何内容

我的代码看起来像:

h1= [{"name"=>"postgresql", "version"=>29}, {"name"=>"java", "version"=>8}, {"name"=>"python", "version"=>3}]

h2= [{"name"=>"postgresql", "release"=>"postgresql-release", "url"=>"https://github.com/repo/postgresql-release"}, {"name"=>"java", "release"=>"java-release", "url"=>"https://github.com/repo/java-release"}]

combined = []

h1.each do |h1Key, h1Value|
  h2.each do |h2Key, h2Value|
    if h1["name"] == h2["name"]
      combined << {"name"=> h1["name"], "version"=> h1["version"], "release"=> h2["release"], "url"=> h2["url"]} 
    else
      combined << {"name"=> h1["name"], "version"=> h1["version"], "release"=> nil, "url"=> nil}
    end
  end
end
puts combined.to_s
h1=[{“name”=>“postgresql”,“version”=>29},{“name”=>“java”,“version”=>8},{“name”=>“python”,“version”=>3}]
h2=[{“名称”=>“postgresql”,“发布”=>“postgresql发布”,“url”=>“https://github.com/repo/postgresql-release},{“name”=>“java”,“release”=>“java release”,“url”=>“https://github.com/repo/java-release"}]
组合=[]
h1.每个do | h1键,h1值|
h2.每个do | h2键,h2值|
如果h1[“名称”]==h2[“名称”]
组合h1[“名称”],“版本”=>h1[“版本”],“发布”=>h2[“发布”],“url”=>h2[“url”]}
其他的
组合h1[“名称”],“版本”=>h1[“版本”],“发布”=>nil,“url”=>nil}
结束
结束
结束
将组合的.to_
我也无法正确比较h1和h2的值

非常感谢您的帮助,因为我对Ruby还很陌生,不幸的是,我的逻辑没有帮到我


提前谢谢^^

首先,h1和h2是散列数组,而不是散列本身。如果对它们进行迭代,则得到数组中的每个散列,而不是某个散列的键和值

为了清楚起见,让我们将它们重命名为
a1
a2

a1= [{"name"=>"postgresql", "version"=>29}, {"name"=>"java", "version"=>8}, {"name"=>"python", "version"=>3}]
a2= [{"name"=>"postgresql", "release"=>"postgresql-release", "url"=>"https://github.com/repo/postgresql-release"}, {"name"=>"java", "release"=>"java-release", "url"=>"https://github.com/repo/java-release"}]

combined = []
现在,当我们迭代它们时,我们依次得到每个散列

a1.each do |h1|
对于第一个数组中的每个哈希,我们希望在第二个数组中找到相应的哈希。如果我们在第一个数组中查看java,在第二个数组中找到postgresql,这并不意味着没有java。我们现在只需要忽略它。如果我们没有找到匹配项,那么我们将分配nil-s

h2 = a2.find { |h| h1["name"] == h["name"] } || {}
现在我们已经找到匹配项或没有找到匹配项,我们可以像您那样将结果添加到组合数组中

combined << {"name"=> h1["name"], "version"=> h1["version"], "release"=> h2["release"], "url"=> h2["url"]}
另一个可能的改进是使用merge

combined = a1.map do |h1|
  h2 = a2.find { |h| h1["name"] == h["name"] } || { "release" => nil, "url" => nil}
  h1.merge(h2)
end
您可以尝试以下代码:

combined = h1
  .concat(h2)
  .group_by { |a| a['name'] }
  .values
  .map do |a|
    res = a.first.merge(a.last)
    res['release'] ||= nil
    res['url'] ||= nil
    res
  end

如果你不确定是什么在做代码,试着一步一步地做。

可能有很多方法可以做到这一点,但由于你的内部哈希基本上有一个键,首先想到的是将你的哈希数组转换成哈希数组,然后简单地使用Hash#deep _merge,这正是做这类事情的方法

hash1 = h1.index_by { |inner_hash| inner_hash['name'] }
hash2 = h2.index_by { |inner_hash| inner_hash['name'] }
combined_hash = hash1.deep_merge(hash2)
combined = combined_hash.values
这将提供除python nil URL之外的预期输出。如果无法在数据中修复该问题,要复制该结果,请尝试以下操作:

combined = [
  {"name"=>"postgresql", "version"=>29, "release"=>"postgresql-release", "url"=>"https://github.com/repo/postgresql-release"},
  {"name"=>"java", "version"=>8, "release"=>"java-release", "url"=>"https://github.com/repo/java-release"},
  {"name"=> "python", "version"=>3, "release"=> nil, "url"=> nil}
]
# ... as before
defaults = {'url' => nil, 'version' => nil}
combined_hash = combined_hash.transform_values { |v| defaults.merge(v) }
combined = combined_hash.values
如果需要将默认值设置为数据中可能更改的精确键:

keys = (hash1.keys + hash2.keys).uniq
defaults = keys.map { |k| [k, nil] }.to_h

您可以使用
索引
,而不是第一个
映射
-s。就是为了这个:
h1.index_by{h | h['name']}
@SiimLiiser Good call,updated.works也很棒!非常感谢^^一切正常。非常感谢您的帮助!我的荣幸。不要犹豫,验证我的答案:)当然我已经这么做了,但我仍然需要15个信誉点,以便其他人看到它。一旦我得到它们,我的验证就可以看到了!哦,好的。^^Thx:)它工作得很好!我已经实现了第一个变体,因为它是目前我最容易理解的,因为我缺乏Ruby方面的知识!)关于这一部分我有一个问题:
h2=a2.find{h}h1[“name”]==h[“name”]}}{code>我不知道到底发生了什么,你能一步一步地再给我解释一下吗?非常感谢你的帮助^^^当然
find
将开始遍历数组并运行块,直到找到块返回的第一个
true
(或任何truthy)为止。然后返回。如果未找到任何内容并到达末尾,则返回
nil
。所以我在第二个数组上迭代,寻找一个同名的散列。如果我找到了,很好。如果没有,我默认为空哈希(
|{}
),因为在空哈希上调用
h2[“release”]
默认返回nil。这使得下面的代码更简单,因为h2始终是散列。然后我就不必检查它是否存在了。医生:很好的解释!!!我现在明白了,提到的医生帮了我更多的忙。非常感谢!!:)