[英]Convert keys in inner hash to keys of outer/parent hash
I have a hash, say, 我有一个哈希,说,
account = {
name: "XXX",
email: "xxx@yyy.com",
details: {
phone: "9999999999",
dob: "00-00-00",
address: "zzz"
}
}
Now I want to convert account
to a hash like this: 现在,我想将
account
转换为像这样的哈希:
account = {
name: "XXX",
email: "xxx@yyy.com",
phone: "9999999999",
dob: "00-00-00",
address: "zzz"
}
I'm a beginner and would like to know if there is any function to do it? 我是一个初学者,想知道是否有任何功能可以执行? (Other than merging the nested hash and then deleting it)
(除了合并嵌套的哈希,然后将其删除)
You could implement a generic flatten_hash
method which works roughly similar to Array#flatten
in that it allows to flatten Hashes of arbitrary depth. 您可以实现一个通用的
flatten_hash
方法,该方法的工作原理与Array#flatten
大致相似,因为它可以展平任意深度的哈希。
def flatten_hash(hash, &block)
hash.dup.tap do |result|
hash.each_pair do |key, value|
next unless value.is_a?(Hash)
flattened = flatten_hash(result.delete(key), &block)
result.merge!(flattened, &block)
end
end
end
Here, we are still performing the delete / merge sequence, but it would be required in any such implementation anyway, even if hidden below further abstractions. 在这里,我们仍在执行删除/合并序列,但是无论如何,即使隐藏在进一步的抽象之下,它仍然是必需的。
You can use this method as follows: 您可以按以下方式使用此方法:
account = {
name: "XXX",
email: "xxx@yyy.com",
details: {
phone: "9999999999",
dob: "00-00-00",
address: "zzz"
}
}
flatten(account)
# => {:name=>"XXX", :email=>"xxx@yyy.com", :phone=>"9999999999", :dob=>"00-00-00", :address=>"zzz"}
Note that with this method, any keys in lower-level hashes overwrite existing keys in upper-level hashes by default. 请注意,使用此方法时,默认情况下,低层哈希中的任何键都会覆盖高层哈希中的现有键。 You can however provide a block to resolve any merge conflicts.
但是,您可以提供一个块来解决任何合并冲突。 Please refer to the documentation of
Hash#merge!
请参考
Hash#merge!
的文档Hash#merge!
to learn how to use this. 学习如何使用它。
这将达到目的:
account.map{|k,v| k==:details ? v : {k => v}}.reduce({}, :merge)
Case 1: Each value of account
may be a hash whose values are not hashes 情况1:每个
account
值可能是一个哈希值,其值不是哈希值
account.flat_map { |k,v| v.is_a?(Hash) ? v.to_a : [[k,v]] }.to_h
#=> {:name=>"XXX", :email=>"xxx@yyy.com", :phone=>"9999999999",
# :dob=>"00-00-00", :address=>"zzz"}
Case 2: account
may have nested hashes 情况2:
account
可能有嵌套的哈希
def doit(account)
recurse(account.to_a).to_h
end
def recurse(arr)
arr.each_with_object([]) { |(k,v),a|
a.concat(v.is_a?(Hash) ? recurse(v.to_a) : [[k,v]]) }
end
account = {
name: "XXX",
email: "xxx@yyy.com",
details: {
phone: "9999999999",
dob: { a: 1, b: { c: 2, e: { f: 3 } } },
address: "zzz"
}
}
doit account
#=> {:name=>"XXX", :email=>"xxx@yyy.com", :phone=>"9999999999", :a=>1,
# :c=>2, :f=>3, :address=>"zzz"}
Explanation for Case 1 情况1的说明
The calculations progress as follows. 计算过程如下。
One way to think of Enumerable#flat_map , as it is used here, is that if, for some method g
, 考虑此处使用的Enumerable#flat_map的一种方法是,如果对于某些方法
g
,
[a, b, c].map { |e| g(e) } #=> [f, g, h]
where a
, b
, c
, f
, g
and h
are all arrays, then 其中
a
, b
, c
, f
, g
和h
都是数组,则
[a, b, c].flat_map { |e| g(e) } #=> [*f, *g, *h]
Let's start by creating an enumerator to pass elements to the block. 让我们从创建一个枚举器开始,将元素传递给该块。
enum = account.to_enum
#=> #<Enumerator: {:name=>"XXX", :email=>"xxx@yyy.com",
# :details=>{:phone=>"9999999999", :dob=>"00-00-00",
# :address=>"zzz"}}:each>
enum
generates an element which is passed to the block and the block variables are set equal to those values. enum
生成一个元素,该元素传递到块,并且块变量设置为等于那些值。
k, v = enum.next
#=> [:name, "XXX"]
k #=> :name
v #=> "XXX"
v.is_a?(Hash)
#=> false
a = [[k,v]]
#=> [[:name, "XXX"]]
k, v = enum.next
#=> [:email, "xxx@yyy.com"]
v.is_a?(Hash)
#=> false
b = [[k,v]]
#=> [[:email, "xxx@yyy.com"]]
k,v = enum.next
#=> [:details, {:phone=>"9999999999", :dob=>"00-00-00", :address=>"zzz"}]
v.is_a?(Hash)
#=> true
c = v.to_a
#=> [[:phone, "9999999999"], [:dob, "00-00-00"], [:address, "zzz"]]
d = account.flat_map { |k,v| v.is_a?(Hash) ? v.to_a : [[k,v]] }
#=> [*a, *b, *c]
#=> [[:name, "XXX"], [:email, "xxx@yyy.com"], [:phone, "9999999999"],
# [:dob, "00-00-00"], [:address, "zzz"]]
d.to_h
#=> <the return value shown above>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.