深层哈希键的组值如何?

时间:2016-06-24 07:22:54

标签: arrays ruby hash grouping

我正在尝试创建一个rake任务,该任务从模型中获取数据并生成类似en.yml的区域设置文件。

例如,输入数据:

[
   {a: {w: 0}, b: '2', c: '3'},
   {a: {q: 1}},
   {aa: {bb: {cc: '4'}}},
   {aa: {bb: {ee: '4'}}}
]

输出数据应如下所示:

    {
      a: {w: 0, q: 1},
      b: '2',
      c: '3',
      aa: {bb: {cc: '4', ee: '4'} }}
    }

因此,应该对同一深层次上相同键的值进行分组。 我怎么能用ruby的数组和哈希方法呢?

3 个答案:

答案 0 :(得分:1)

您可以对nasted哈希结构使用递归方法。

require 'yaml'

def group_by_keys(sub_hash, export)
  sub_hash.each do |k, v|
    if Hash === v
      export[k] ||= {}
      self.send(__method__, v, export[k])
    else
      export[k] = v
    end
  end
end

yaml = "[
   {a: {w: 0}, b: '2', c: '3'},
   {a: {q: 1}},
   {aa: {bb: {cc: '4'}}},
   {aa: {bb: {ee: '4'}}}
]"

imput = YAML.load(yaml)

export = imput.each_with_object({}){|sub_hash, exp| group_by_keys(sub_hash, exp)}

导出

p export

# {
#   "a" => {"w" => 0, "q" => 1},
#   "b" => "2",
#   "c" => "3",
#   "aa" => {
#     "bb" => {"cc" => "4", "ee" => "4"}
#   }
# }

我希望这会有所帮助

答案 1 :(得分:1)

Rails Active Support Core扩展,Hash#deep_merge完成相同的工作。你可以利用那颗宝石,而不是重新发明轮子。

require "active_support/core_ext/hash"
arr = [
   {a: {w: 0}, b: '2', c: '3'},
   {a: {q: 1}},
   {aa: {bb: {cc: '4'}}},
   {aa: {bb: {ee: '4'}}}
]

p arr.reduce {|h1, h2| h1.deep_merge(h2)}
#=> {:a=>{:w=>0, :q=>1}, :b=>"2", :c=>"3", :aa=>{:bb=>{:cc=>"4", :ee=>"4"}}}

如果您不想使用gem,可以从Rails code base here复制deep_merge的代码。

答案 2 :(得分:0)

# No gems needed, to scale however you'll need to add code
hash_array = [{a: {w: 0}, b: "2", c: "3"}, {a: {q: 1}}, {aa: {bb: {cc:"4"}}}, {aa: {bb: {ee: "4" }}}]

new_hash = {}
test_array = []
hash_array.each do |hashes|
  if test_array.include?(hashes.keys[0])
    if hashes.values[0].values[0].class == Hash
      merge_this = hashes.values[0].values[0]
      new_hash[hashes.keys[0]].values[0].merge!(merge_this)
    else
      new_hash[hashes.keys[0]].merge!(hashes.values[0])
    end
  else
    new_hash.merge!(hashes)
  end
  test_array << hashes.keys[0]
end
# You can easily move braces into standard .yml format
p new_hash # returns {:a=>{:w=>0, :q=>1}, :b=>"2", :c=>"3", :aa=>{:bb=>{:cc=>"4", :ee=>"4"}}}