【问题标题】:Converting a multi-level hash into a single hash将多级散列转换为单个散列
【发布时间】:2018-01-14 19:55:53
【问题描述】:

我有一个源哈希:

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,但它们没有给出正确的结果。

感谢任何帮助。

【问题讨论】:

  • 更新了问题! @kabanus:没看到!谢谢。

标签: ruby hash


【解决方案1】:
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 }
}

【讨论】:

  • 不错的递归。值得注意的是,对应的递归方法是将第一行替换为def compact_hash(hh, h0={}),将最后一行(})替换为end。此外,如果你使用hh.each_with_object(h0) do |(k, v),h|,你可以摆脱那条讨厌的线h(也许让它成为一个三元语句)。
  • @CarySwoveland 非常感谢! h 让我很烦。
  • 每当我收到可以改进我的答案的建议时,我都会从头开始重写我的答案,并在评论中感谢评论者。我认为这比保留我的原始答案的内容并注意到建议的改进更好地为读者服务。如果我们正在写一本书或博客并以草稿形式分发以征求意见,那么我们所有人都会这样做(也许除了归属之外),那么为什么不寻求 SO 答案呢?
【解决方案2】:
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) }

我不知道哪个效率更高。

【讨论】:

    【解决方案3】:
    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"}
    

    【讨论】:

      猜你喜欢
      • 2013-05-16
      • 1970-01-01
      • 2016-09-04
      • 2023-03-07
      • 2016-07-18
      • 2020-06-29
      • 2011-08-21
      • 2012-03-27
      • 1970-01-01
      相关资源
      最近更新 更多