[英]How to get values from hash for only specific keys stored in array
我希望能够通过使用存储在数组中的键来仅从哈希中获取元素。
我有一个哈希:
my_hash = { "2222"=> {"1111"=> "1"}, "2223"=>{"1113"=> "2"}, "12342"=> {"22343"=> "3"}}
要么
my_hash2 = { "2222"=>"1", "1111"=> "2", "12342"=> "3"}
和一个数组:
my_array = ['2223','1113']
my_array2 = ['12342']
my_array
代表my hash
的链接键。 my_hash的级别可以从1到...变化,因此my_array的长度也将变化。 因此,我需要一个通用的解决方案(不仅适用于两个级别的哈希)。
我的想法是做这样的事情,但这是错误的。
my_hash[my_array] = '2'
my_hash2[my_array2] = '3'
实际上,我希望能够设置这些值。 my_hash[my_array] = '5'
会将my_hash["2223"]["2223"]
的值设置为5
您可以使用Hash#dig
方法。
my_hash = { "2222"=> {"1111"=> "1"}, "2223"=>{"1113"=> "2"}, "12342"=> {"22343"=> "3"}}
my_hash.dig("2222", "1111")
# => 1
my_array = ["2222", "1111"]
my_hash.dig(*my_array) # with the splat operator
# => 1
请注意, Hash#dig
仅存在于Ruby 2.3+中。 如果您使用的是旧版本,则无法使用。
Hash#dig是在Ruby v2.3中首次亮相的。 如果您需要支持Ruby的早期版本,则可以使用Enumerable#reduce (又名inject
)。
def burrow(h, a)
a.reduce(h) { |g,k| g && g[k] }
end
h = {"2222"=>{"1111"=>"1"}, "2223"=>{"1113"=>"2"}, "12342"=>{"22343"=>"3"}}
burrow(h, ['2223','1113']) #=> "2"
burrow(h, ['2223']) #=> {"1113"=>"2"}
burrow(h, ['2223','cat']) #=> nil
burrow(h, ['cat','1113']) #=> nil
之所以起作用,是因为如果对于k
中a
某些元素k
,由块变量g
(“ memo”)给出的哈希值没有键k
,则g[k] #=> nil
,因此nil
成为备忘录的值g
并且对于传递给该块的a
所有后续值,将保持nil
。 这就是我小时候通常进行挖掘的方式。
要更改适当的值,我们可以执行以下操作。
def burrow_and_update(h, a, v)
*arr, last = a
f = arr.reduce(h) { |g,k| g && g[k] }
return nil unless f.is_a?(Hash) && f.key?(last)
f[last] = v
end
burrow_and_update(h, ['2223','1113'], :cat) #=> :cat
h #=> {"2222"=>{"1111"=>"1"}, "2223"=>{"1113"=>:cat}, "12342"=>{"22343"=>"3"}}
h = {"2222"=>{"1111"=>"1"}, "2223"=>{"1113"=>"2"}, "12342"=>{"22343"=>"3"}} # reset h
burrow_and_update(h, ['2223', :dog], :cat)
#=> nil
在第二种情况下,由于{"1113"=>"2"}
没有键:dog
所以返回nil
。
要检索该值,可以按照其他答案中的建议使用Hash#dig
。
如果您想更新哈希,那么,您将需要做更多的工作-这是一种实现方法:
my_hash = { "2222"=> {"1111"=> "1"}, "2223"=>{"1113"=> "2"}, "12342"=> {"22343"=> "3"}}
my_array = ['2223','1113']
target_hash = my_array.length > 1 ?
my_hash.dig(*my_array[0, my_array.length - 1]) :
my_hash
target_hash[my_array.last] = "5"
p my_hash
#=> {"2222"=>{"1111"=>"1"}, "2223"=>"5", "12342"=>{"22343"=>"3"}}
如果我知道代码将在具有dig
功能的Ruby上运行,我将使用dig
,但要回退,我将使用类似以下的方法:
class Hash
def deep_get(*keys)
o = self
keys.each { |k| o = o[k] }
o
end
def deep_set(*keys, v)
o = self
keys[0..-2].each { |k| o = o[k] }
o[keys.last] = v
end
end
my_hash = { "2222"=> {"1111"=> "1"}, "2223"=>{"1113"=> "2"}, "12342"=> {"22343"=> "3"}}
my_array = ['2223','1113']
my_hash.deep_get(*my_array) # => "2"
根据my_array
分配给哈希:
my_hash.deep_set(*my_array, '4')
my_hash.deep_get(*my_array) # => "4"
my_hash # => {"2222"=>{"1111"=>"1"}, "2223"=>{"1113"=>"4"}, "12342"=>{"22343"=>"3"}}
当然,最近不建议修补哈希。 您应该改用“ 优化”功能,但是如果这些功能不可用,则必须对其进行修补。
这段代码不会尝试处理错误,例如,如果键数组与哈希中的键不匹配。 如何处理以及返回什么,让您自己弄清楚。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.