在哈希数组内部合并哈希 [英] Merge Hashes within Array of Hashes

查看:156
本文介绍了在哈希数组内部合并哈希的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  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



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



使用 Enumerable#group_by

  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.

Use Enumerable#group_by

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆