我希望能够通过使用存储在数组中的键来仅从哈希中获取元素。
我有一个哈希:
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
答案 0 :(得分:2)
您可以使用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+中。如果您使用的是旧版本,则无法使用。
答案 1 :(得分:1)
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
,如果块变量g
(“备忘录”)给出的哈希没有键{{1} },k
,因此g[k] #=> nil
成为备忘录nil
的值,并且对于传递给块的g
的所有后续值将保持nil
。这就是我小时候通常进行的挖掘工作。
要更改值,我们可以执行以下操作。
a
在第二种情况下,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
会被返回,因为nil
没有密钥{"1113"=>"2"}
。
答案 2 :(得分:0)
要检索该值,您可以按照other answer中的建议使用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"}}
答案 3 :(得分:0)
如果我知道代码将在可用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"}}
当然,这些天不推荐修补Hash。您应该使用Refinements,但如果这些不可用,那么您必须对其进行修补。
此代码不会尝试处理错误,例如键的数组与散列中的键不匹配。如何处理以及返回的内容留待您了解。