在哈希数组内部合并哈希 [英] Merge Hashes within Array of Hashes
问题描述
hash = Modality.joins (:exam).where(考试:{physician_id:physician})。map {| m |
{名称: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,2017年1月1日=> 1}},
{:name =>MR,:data => {Wed,2017年2月01日=> 41} },
{:name =>CT,:data => {Wed,2017年2月01日=> 4}},
{:name =>MR = {2017年3月1日=> 66}},
{:姓名=>CT,:data => {Wed,01 Mar 2017 => 6}},
{:name =>XR,:data => {Wed,01 Mar 2017 => 1}},
{:name =>CT,:data => {星期六,2017年4月1日=> 8}},
{:姓名=>美国,:data => {Sat,2017年4月1日=> 1}},
{姓名=>MR,:data => {Sat,2017年4月1日=> 73}},
{:姓名=>CT,:data => {Sun, 2017年1月1日=> 44}},
{:name => 52}},
{:name =>MR,:data => US,:data => {Sun,2017年1月1日=> 1}}
]
我需要根据名称键对散列的数据部分进行分组和合并,如下所示:
[
{:name =>MR,:data => {Sun,01 Jan 2017 => 2017年2月1日星期三=> 41,2017年3月01日星期三=> 66,2017年4月01日星期六=> 73,星期日,2017年1月01日=> 44}}
{:姓名=> ;CT,:data => {Sun,2017年1月1日=> 7,2017年2月01日星期三=> 4,2017年3月01日星期三=> 6,2017年4月01日星期六=> 8 ,Sun,2017年1月1日=> 52}}
{:name =>US,:data => {Sun,2017年1月1日=> 1, 1,Sun,01 Jan 2017 => 1}}
{:name =>XR,:data => {Wed,01 Mar 2017 => 1}}
]
我尝试减少和合并,如下所示:
考试= hash.group_by {| d | d [:name]}。map {| k,v | v.reduce(:merge)}
但它不是所需的输出:
[
{:name =>MR,:data => {Sun,01 Jan, 2017年1月1日=> 52}},
{:姓名=> 44}},
{:姓名=>CT,::data => US,:data => {Sun,2017年1月1日=> 1}},
{:name =>XR,:data => {Wed,01 Mar 2017 => 1}}
]
如何正确合并这个散列?
a
,我已经缩小了大小并放置了日期在引号中。 arr = [
{:name =>MR,:data => { 2017年1月01日=> 44}},
{:姓名=>CT,:data => {Sun,2017年1月1日=> 7} :name =>US,:data => {Sun,2017年1月1日=> 1}},
{:name =>MR,:data => {星期三,2017年2月1日=> 41}},
{:姓名=>CT,:data => {Wed,01 Feb 2017=> 4}},
{:name =>CT,:data => {Wed,2017年3月01日=> 6}},
{:name =>XR,:data => {Wed,01 Mar 2017=> 1}},
{:name =>US,:data => {Sat,2017年4月1日=> 1}}
]
将日期字符串转换为 Date
objects 1 ,但我不会这样做,因为下面的方法不依赖于日期是字符串还是 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,2017年1月1日=> 44,2017年2月01日星期三=> 41}},
#{:姓名=>CT,:data => {Sun,2017年1月1日=> 7,Wed,01 Feb 2017=> 4,
# => 6}},
#{:name =>US,:data => {Sun,01 Jan 2017=> 1, 1}},
#{:name =>XR,:data => {Wed,01 Mar 2017=> 1}}]
请注意, Enumerable#group_by
会产生以下散列。
arr.group_by {| h | h [:name]}
#=> {MR=> [{:name =>MR,:data => {Sun,2017-01-01=> 44}},
#{:name => MR,:data => {Wed,01 Feb 2017=> 41}}],
#CT=> [{:name =>CT,:data => ; {Sun,2017年1月1日=> 7}},
#{:name =>CT,:data => {Wed,2017年2月01日=> 4}} ,
#{:name =>CT,:data => {Wed,01 Mar 2017=> 6}}],
#US=> [{ :name =>US,:data => {Sun,2017年1月1日=> 1}},
#{:name =>US,:data => { Sun,01 Jan 2017=> 1}}]
#XR=> [{:name =>XR,:data => { => 1}}]}
可以替代
v.reduce({}){| h,g | h.merge(g [:data])}
with
v.map {| h | h [:data]} .reduce(& merge)
使用 Hash#update (aka 合并!
)和哈希#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,2017年1月1日=> 44,2017年2月01日星期三=> 41}},
#{:姓名=>CT,:data => {Sun,2017年1月1日=> 7,Wed,01 Feb 2017=> 4,
# => 6}},
#{:name =>US,:data => {Sun,01 Jan 2017=> 1, 1}},
#{:name =>XR,:data => {Wed,01 Mar 2017=> 1}}]
它使用 Hash#update
的形式,它使用一个块来确定键的值存在于被合并的两个哈希中。有关详细信息,请参阅方法的文档,特别是三个块变量的定义: _
, o
和ñ
。 (保存公共密钥的第一个块变量在这里用下划线[一个有效的局部变量]表示,以表示它在块计算中不被使用)。
1 需要'date'; arr = a.map do | h |;键,值= h [:data] .flatten; h.merge(data:{Date.parse(key)=> value});结束
I'm generating an array of hashes like this:
hash = Modality.joins(:exam).where(exams: {physician_id: physician}).map {|m|
{name: m.name, data: {m.exam.from_date => m.total}}
}
The output:
[
{: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=>"CT", :data=>{Sun, 01 Jan 2017=>52}},
{:name=>"MR", :data=>{Sun, 01 Jan 2017=>44}},
{:name=>"US", :data=>{Sun, 01 Jan 2017=>1}}
]
I need to group and merge the data part of the hash based on the name key like this:
[
{:name=>"MR", :data=>{Sun, 01 Jan 2017=>44, Wed, 01 Feb 2017=>41, Wed, 01 Mar 2017=>66, Sat, 01 Apr 2017=>73, Sun, 01 Jan 2017=>44}}
{:name=>"CT", :data=>{Sun, 01 Jan 2017=>7, Wed, 01 Feb 2017=>4, Wed, 01 Mar 2017=>6, Sat, 01 Apr 2017=>8, Sun, 01 Jan 2017=>52}}
{:name=>"US", :data=>{Sun, 01 Jan 2017=>1, Sat, 01 Apr 2017=>1, Sun, 01 Jan 2017=>1}}
{:name=>"XR", :data=>{Wed, 01 Mar 2017=>1}}
]
I tried reducing and merging like this:
exams = hash.group_by {|d| d[:name]}.map {|k, v| v.reduce(:merge)}
But it's not the desired output:
[
{:name=>"MR", :data=>{Sun, 01 Jan 2017=>44}},
{:name=>"CT", :data=>{Sun, 01 Jan 2017=>52}},
{:name=>"US", :data=>{Sun, 01 Jan 2017=>1}},
{:name=>"XR", :data=>{Wed, 01 Mar 2017=>1}}
]
How would I correctly merge this hash?
Here is your array a
, which I've reduced in size and put the dates in quotes.
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}}
]
A simple modification is required to convert the date strings to Date
objects1, but I will not do that as the methods below do not depend on whether the dates are strings or Date
objects.
Here are two ways to obtain the desired return value.
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}}]
Note that Enumerable#group_by
produces the following hash.
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}}]}
One could alternatively replace
v.reduce({}) { |h,g| h.merge(g[:data]) }
with
v.map { |h| h[:data] }.reduce(&:merge)
Use Hash#update (aka merge!
) and Hash#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}}]
This uses the form of Hash#update
that employs a block for determining the values of keys that are present in both hashes being merged. See the method's doc for details, particularly the definitions of the three block variables, _
, o
and n
. (The first block variable, which holds the common key, is here represented by an underscore [a valid local variable] to signify that it is not used in the block calculation.)
1 require 'date'; arr = a.map do |h|; key, value = h[:data].flatten; h.merge(data: { Date.parse(key)=>value }); end
这篇关于在哈希数组内部合并哈希的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!