如何使哈希变平,使每个键具有唯一值? [英] How to flatten a hash, making each key a unique value?

查看:88
本文介绍了如何使哈希变平,使每个键具有唯一值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用带有嵌套哈希和数组的哈希,然后将其展平为具有唯一值的单个哈希.我一直试图从不同的角度来解决这个问题,但是后来我使它变得比实际需要的更加复杂,并使自己迷失在正在发生的事情中.

I want to take a hash with nested hashes and arrays and flatten it out into a single hash with unique values. I keep trying to approach this from different angles, but then I make it way more complex than it needs to be and get myself lost in what's happening.

示例源哈希:

{
  "Name" => "Kim Kones",
  "License Number" => "54321",
  "Details" => {
    "Name" => "Kones, Kim",
    "Licenses" => [
      {
        "License Type" => "PT",
        "License Number" => "54321"
      },
      {
        "License Type" => "Temp",
        "License Number" => "T123"
      },
      {
        "License Type" => "AP",
        "License Number" => "A666",
        "Expiration Date" => "12/31/2020"
      }
    ]
  }
}

示例所需的哈希值:

{
  "Name" => "Kim Kones",
  "License Number" => "54321",
  "Details_Name" => "Kones, Kim",
  "Details_Licenses_1_License Type" => "PT",
  "Details_Licenses_1_License Number" => "54321",
  "Details_Licenses_2_License Type" => "Temp",
  "Details_Licenses_2_License Number" => "T123",
  "Details_Licenses_3_License Type" => "AP",
  "Details_Licenses_3_License Number" => "A666",
  "Details_Licenses_3_Expiration Date" => "12/31/2020"
}

对于它的价值,这是我放弃之前的最新尝试.

For what it's worth, here's my most recent attempt before giving up.

def flattify(hashy)
    temp = {}
    hashy.each do |key, val|
        if val.is_a? String
            temp["#{key}"] = val
        elsif val.is_a? Hash
            temp.merge(rename val, key, "")
        elsif val.is_a? Array
            temp["#{key}"] = enumerate val, key
        else
        end
        print "=> #{temp}\n"
    end
    return temp
end

def rename (hashy, str, n)
    temp = {}
    hashy.each do |key, val|
        if val.is_a? String
            temp["#{key}#{n}"] = val
        elsif val.is_a? Hash
            val.each do |k, v|
                temp["#{key}_#{k}#{n}"] = v
            end
        elsif val.is_a? Array
            temp["#{key}"] = enumerate val, key
        else

        end
    end
    return flattify temp
end

def enumerate (ary, str)
    temp = {}
    i = 1
    ary.each do |x|
        temp["#{str}#{i}"] = x
        i += 1
    end
    return flattify temp
end

推荐答案

有趣的问题!

这是解析数据的递归方法.

Here's a recursive method to parse your data.

  • 它跟踪找到的键和索引.
  • 它将它们附加到tmp数组中.
  • 一旦找到叶对象,它就会以哈希值作为值写入,并以连接的tmp作为键.
  • 然后,此小哈希将递归合并回主哈希.
  • It keeps track of which keys and indices it has found.
  • It appends them in a tmp array.
  • Once a leaf object has been found, it gets written in a hash as value, with a joined tmp as key.
  • This small hash then gets recursively merged back to the main hash.
def recursive_parsing(object, tmp = [])
  case object
  when Array
    object.each.with_index(1).with_object({}) do |(element, i), result|
      result.merge! recursive_parsing(element, tmp + [i])
    end
  when Hash
    object.each_with_object({}) do |(key, value), result|
      result.merge! recursive_parsing(value, tmp + [key])
    end
  else
    { tmp.join('_') => object }
  end
end

例如:

require 'pp'
pp recursive_parsing(data)
# {"Name"=>"Kim Kones",
#  "License Number"=>"54321",
#  "Details_Name"=>"Kones, Kim",
#  "Details_Licenses_1_License Type"=>"PT",
#  "Details_Licenses_1_License Number"=>"54321",
#  "Details_Licenses_2_License Type"=>"Temp",
#  "Details_Licenses_2_License Number"=>"T123",
#  "Details_Licenses_3_License Type"=>"AP",
#  "Details_Licenses_3_License Number"=>"A666",
#  "Details_Licenses_3_Expiration Date"=>"12/31/2020"}

调试

这是经过旧式调试的修改版本.它可以帮助您了解正在发生的事情:

Debugging

Here's a modified version with old-school debugging. It might help you understand what's going on:

def recursive_parsing(object, tmp = [], indent="")
  puts "#{indent}Parsing #{object.inspect}, with tmp=#{tmp.inspect}"
  result = case object
  when Array
    puts "#{indent} It's an array! Let's parse every element:"
    object.each_with_object({}).with_index(1) do |(element, result), i|
      result.merge! recursive_parsing(element, tmp + [i], indent + "  ")
    end
  when Hash
    puts "#{indent} It's a hash! Let's parse every key,value pair:"
    object.each_with_object({}) do |(key, value), result|
      result.merge! recursive_parsing(value, tmp + [key], indent + "  ")
    end
  else
    puts "#{indent} It's a leaf! Let's return a hash"
    { tmp.join('_') => object }
  end
  puts "#{indent} Returning #{result.inspect}\n"
  result
end

recursive_parsing([{a: 'foo', b: 'bar'}, {c: 'baz'}])调用时,显示:

Parsing [{:a=>"foo", :b=>"bar"}, {:c=>"baz"}], with tmp=[]
 It's an array! Let's parse every element:
  Parsing {:a=>"foo", :b=>"bar"}, with tmp=[1]
   It's a hash! Let's parse every key,value pair:
    Parsing "foo", with tmp=[1, :a]
     It's a leaf! Let's return a hash
     Returning {"1_a"=>"foo"}
    Parsing "bar", with tmp=[1, :b]
     It's a leaf! Let's return a hash
     Returning {"1_b"=>"bar"}
   Returning {"1_a"=>"foo", "1_b"=>"bar"}
  Parsing {:c=>"baz"}, with tmp=[2]
   It's a hash! Let's parse every key,value pair:
    Parsing "baz", with tmp=[2, :c]
     It's a leaf! Let's return a hash
     Returning {"2_c"=>"baz"}
   Returning {"2_c"=>"baz"}
 Returning {"1_a"=>"foo", "1_b"=>"bar", "2_c"=>"baz"}

这篇关于如何使哈希变平,使每个键具有唯一值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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