将多级哈希转换为单个哈希

时间:2018-01-14 19:55:54

标签: ruby hash

我有一个源哈希:

a = {'1' => 'A',
     '2' => 'B',
     '3' => 'C',
     '4' => { '5' => 'D', '6' => 'E', '7' => { '8' => 'F', '9' => 'G' }},
     '10' => {'11' => 'H'}}

我需要构造一个方法来使它成为一个平面哈希(单个哈希)。结果应如下所示:

a = {'1' => 'A', '2' => 'B', '3' => 'C', '5' => 'D', '6' => 'E', '8' => 'F', '9' => 'G', '11' => 'H'}

我尝试使用mergedeep_mergeeach_with_objectrecursion,但他们没有给出正确的结果。

感谢任何帮助。

3 个答案:

答案 0 :(得分:2)

a = {'1' => 'A',
     '2' => 'B',
     '3' => 'C',
     '4' => { '5' => 'D', '6' => 'E', '7' => { '8' => 'F', '9' => 'G' }},
     '10' => {'11' => 'H'}}

# recursive detect value is Hash or not
compact_hash = ->(hh, h0={}) {
    hh.reduce(h0) do |h, (k, v)|
        if v.is_a? Hash
            compact_hash[v, h]
        else
            h[k] = v
            h
        end
    end
}

puts compact_hash[a]

非常感谢@cary,我知道如何在没有;的情况下执行单行并删除h

compact_hash = ->(hh, h0={}) {
    hh.each_with_object(h0) { |(k, v), h | v.is_a?(Hash) ? compact_hash[v, h] : h[k] = v }
}

答案 1 :(得分:1)

h = { '1' => 'A', '2' => 'B', '3' => 'C',
      '4' => { '5' => 'D', '6' => 'E', '7' => { '8' => 'F', '9' => 'G' } },
     '10' => { '11' => 'H'} }

hh = h.dup    
loop do
  g = hh.select { |_,v| v.is_a? Hash }
  break hh if g.empty?
  g.keys.each { |k| hh.delete(k) }
  g.values.each { |f| hh.update(f) }
end
  #=> {"1"=>"A", "2"=>"B", "3"=>"C", "5"=>"D", "6"=>"E", "11"=>"H", "8"=>"F", "9"=>"G"}

这不会改变h

h #=> { "1"=>"A", "2"=>"B", "3"=>"C",
  #     "4"=>{"5"=>"D", "6"=>"E", "7"=>{"8"=>"F", "9"=>"G"}},
  #    "10"=>{"11"=>"H"}}

倒数第三行可以替换为以下内容。

g_keys = g.keys
hh.delete_if  { |k| g_keys.include?(k) }

我不知道效率会更高。

答案 2 :(得分:0)

a = {'1' => 'A',
     '2' => 'B',
     '3' => 'C',
     '4' => { '5' => 'D', '6' => 'E', '7' => { '8' => 'F', '9' => 'G' }},
     '10' => {'11' => 'H'}}

def flatten_hash(hash)
  hash.each_pair.reduce({}) do |h, (k, v)|
    v.is_a?(Hash) ? h.merge(flatten_hash(v)) : h.merge(k => v)
  end
end

# pry(main)> flatten_hash(a)
#=> {"1"=>"A", "2"=>"B", "3"=>"C", "5"=>"D", "6"=>"E", "8"=>"F", "9"=>"G", "11"=>"H"}