按键分组哈希值并连接值

时间:2018-02-23 01:40:34

标签: ruby hash

我需要按键对哈希进行分组并连接值。例如,给定此哈希:

[
  {"name": "FT002", "data": {"2017-11-01": 1392.0}},
  {"name": "FT004", "data": {"2017-11-01": 4091.0}},
  {"name": "FT002", "data": {"2017-12-01": 1279.0}},
  {"name": "FT004", "data": {"2017-12-01": 3249.0}}
]

我想生成这个哈希:

[
  {"name": "FT002", "data": {"2017-11-01": 1392.0, "2017-12-01": 1279.0}},
  {"name": "FT004", "data": {"2017-11-01": 4091.0, "2017-12-01": 3249.0}}
]

任何帮助都将不胜感激。

我尝试了injectgroup_bymerge的各种迭代,但似乎无法获得正确的结果。

3 个答案:

答案 0 :(得分:1)

您可以在三个简短的单行中完成此操作,首先生成哈希映射名称到数据,然后生成所需的结构:

data = [
  {"name":"FT002","data":{"2017-11-01":1392.0}},
  {"name":"FT004","data":{"2017-11-01":4091.0}},
  {"name":"FT002","data":{"2017-12-01":1279.0}},
  {"name":"FT004","data":{"2017-12-01":3249.0}}
]

hash = Hash.new { |hash,key| hash[key] = {} }

data.each { |name:, data:| hash[name].merge!(data) }

hash = hash.map { |k,v| { name: k, data: v } }

答案 1 :(得分:1)

data.group_by { |h| h[:name] }.map do |k,arr|
  { name: k, data: arr.each_with_object({}) { |g,h| h.update(g[:data]) } }
end
  #=> [{:name=>"FT002", :data=>{:"2017-11-01"=>1392.0, :"2017-12-01"=>1279.0}},
  #    {:name=>"FT004", :data=>{:"2017-11-01"=>4091.0, :"2017-12-01"=>3249.0}}]

第一步是使用Enumerable#group_by生成以下哈希值。

data.group_by { |h| h[:name] }
  #=> {"FT002"=>[
  #               {:name=>"FT002", :data=>{:"2017-11-01"=>1392.0}},
  #               {:name=>"FT002", :data=>{:"2017-12-01"=>1279.0}}
  #             ],
  #    "FT004"=>[
  #               {:name=>"FT004", :data=>{:"2017-11-01"=>4091.0}},
  #               {:name=>"FT004", :data=>{:"2017-12-01"=>3249.0}}
  #             ]
  #   }

第二步是简单地操纵此哈希的键和值。请参阅Hash#update(又名merge!)。

第二步的替代方法如下。

data.group_by { |h| h[:name] }.map do |k,arr|
  { name: k, data: arr.map { |g| g[:data].flatten }.to_h }
end

请注意,这使用的是Hash#flatten,而不是Array#flatten

答案 2 :(得分:-1)

这应该会产生您正在寻找的结果:

data = [
  {"name":"FT002","data":{"2017-11-01":1392.0}},
  {"name":"FT004","data":{"2017-11-01":4091.0}},
  {"name":"FT002","data":{"2017-12-01":1279.0}},
  {"name":"FT004","data":{"2017-12-01":3249.0}}
]

newData = {}

data.each do |x|
  newData[x[:name]] = [] unless newData[x[:name]].present?
  newData[x[:name]].push x[:data]
end

combined = []
newData.each do |index,value|
  dateData = {}
  value.each do |dateStuff|
    dateStuff.each do |dateIndex, dateValue|
      dateData[dateIndex] = dateValue
    end
  end
  values = {"name": index, "data": dateData}
  combined.push values
end

combined