在哈希数组中合并哈希值

时间:2018-05-17 02:40:00

标签: ruby-on-rails arrays ruby hash

我正在生成一系列像这样的哈希:

hash = Modality.joins(:exam).where(exams: {physician_id: physician}).map {|m|
  {name: m.name, data: {m.exam.from_date => m.total}}
}

输出:

[
  {:name=>"MR", :data=>{Sun, 01 Jan 2017=>44}}, 
  {:name=>"CT", :data=>{Sun, 01 Jan 2017=>7}}, 
  {:name=>"US", :data=>{Sun, 01 Jan 2017=>1}}, 
  {:name=>"MR", :data=>{Wed, 01 Feb 2017=>41}}, 
  {:name=>"CT", :data=>{Wed, 01 Feb 2017=>4}}, 
  {:name=>"MR", :data=>{Wed, 01 Mar 2017=>66}}, 
  {:name=>"CT", :data=>{Wed, 01 Mar 2017=>6}}, 
  {:name=>"XR", :data=>{Wed, 01 Mar 2017=>1}}, 
  {:name=>"CT", :data=>{Sat, 01 Apr 2017=>8}}, 
  {:name=>"US", :data=>{Sat, 01 Apr 2017=>1}}, 
  {:name=>"MR", :data=>{Sat, 01 Apr 2017=>73}}
]

我需要根据名称键对哈希的数据部分进行分组和合并,如下所示:

[
  {:name=>"MR", :data=>{Sun, 01 Jan 2017=>44, Wed, 01 Feb 2017=>41, Wed, 01 Mar 2017=>66, Sat, 01 Apr 2017=>73}}
  {:name=>"CT", :data=>{Sun, 01 Jan 2017=>7, Wed, 01 Feb 2017=>4, Wed, 01 Mar 2017=>6, Sat, 01 Apr 2017=>8}}
  {:name=>"US", :data=>{Sun, 01 Jan 2017=>1, Sat, 01 Apr 2017=>1, Sun}}
  {:name=>"XR", :data=>{Wed, 01 Mar 2017=>1}}
]

我尝试像这样缩小和合并:

exams = hash.group_by {|d| d[:name]}.map {|k, v| v.reduce(:merge)}

但这不是理想的输出:

[
  {:name=>"MR", :data=>{Sun, 01 Jan 2017=>44}}, 
  {:name=>"CT", :data=>{Sun, 01 Jan 2017=>7}}, 
  {:name=>"US", :data=>{Sun, 01 Jan 2017=>1}}, 
  {:name=>"XR", :data=>{Wed, 01 Mar 2017=>1}}
]

我如何正确合并此哈希?

1 个答案:

答案 0 :(得分:1)

这是您的数组a,我已将其缩小并将日期放在引号中。

arr = [
  {:name=>"MR", :data=>{"Sun, 01 Jan 2017"=>44}}, 
  {:name=>"CT", :data=>{"Sun, 01 Jan 2017"=>7}}, 
  {:name=>"US", :data=>{"Sun, 01 Jan 2017"=>1}}, 
  {:name=>"MR", :data=>{"Wed, 01 Feb 2017"=>41}}, 
  {:name=>"CT", :data=>{"Wed, 01 Feb 2017"=>4}}, 
  {:name=>"CT", :data=>{"Wed, 01 Mar 2017"=>6}}, 
  {:name=>"XR", :data=>{"Wed, 01 Mar 2017"=>1}},
  {:name=>"US", :data=>{"Sat, 01 Apr 2017=>1}}
]

将日期字符串转换为Date个对象 1 需要进行简单修改,但我不会这样做,因为下面的方法不依赖于日期是字符串还是{ {1}}对象。

以下是获得所需回报值的两种方法。

使用Enumerable#group_by

Date

请注意arr.group_by { |h| h[:name] }. map { |k,v| { name: k, data: v.reduce({}) { |h,g| h.merge(g[:data]) } } } #=> [{:name=>"MR", :data=>{"Sun, 01 Jan 2017"=>44, "Wed, 01 Feb 2017"=>41}}, # {:name=>"CT", :data=>{"Sun, 01 Jan 2017"=>7, "Wed, 01 Feb 2017"=>4, # "Wed, 01 Mar 2017"=>6}}, # {:name=>"US", :data=>{"Sun, 01 Jan 2017"=>1, "Sat, 01 Apr 2017"=>1}}, # {:name=>"XR", :data=>{"Wed, 01 Mar 2017"=>1}}] 会产生以下哈希值。

Enumerable#group_by

可以替代

arr.group_by { |h| h[:name] }
  #=> {"MR"=>[{:name=>"MR", :data=>{"Sun, 01 Jan 2017"=>44}},
  #           {:name=>"MR", :data=>{"Wed, 01 Feb 2017"=>41}}],
  #    "CT"=>[{:name=>"CT", :data=>{"Sun, 01 Jan 2017"=>7}},
  #           {:name=>"CT", :data=>{"Wed, 01 Feb 2017"=>4}},
  #           {:name=>"CT", :data=>{"Wed, 01 Mar 2017"=>6}}],
  #    "US"=>[{:name=>"US", :data=>{"Sun, 01 Jan 2017"=>1}},
  #           {:name=>"US", :data=>{"Sun, 01 Jan 2017"=>1}}],
  #    "XR"=>[{:name=>"XR", :data=>{"Wed, 01 Mar 2017"=>1}}]}

v.reduce({}) { |h,g| h.merge(g[:data]) }

使用Hash#update(又名v.map { |h| h[:data] }.reduce(&:merge) )和Hash#merge

merge!

这使用arr.each_with_object({}) do |g,h| h.update(g[:name]=>g) { |_,n,o| { name: n[:name], data: n[:data].merge(o[:data]) } } end.values #=> [{:name=>"MR", :data=>{"Sun, 01 Jan 2017"=>44, "Wed, 01 Feb 2017"=>41}}, # {:name=>"CT", :data=>{"Sun, 01 Jan 2017"=>7, "Wed, 01 Feb 2017"=>4, # "Wed, 01 Mar 2017"=>6}}, # {:name=>"US", :data=>{"Sun, 01 Jan 2017"=>1, "Sat, 01 Apr 2017"=>1}}, # {:name=>"XR", :data=>{"Wed, 01 Mar 2017"=>1}}] 的形式,它使用一个块来确定合并的两个哈希中存在的键的值。有关详细信息,请参阅方法文档,尤其是三个块变量Hash#update_o的定义。 (第一个包含公共密钥的块变量在这里用下划线[有效的局部变量]表示,表示它不用于块计算。)

1 n