如何从散列中获取仅存储在数组中的特定键的值

时间:2017-01-12 15:13:07

标签: arrays ruby hash

我希望能够通过使用存储在数组中的键来仅从哈希中获取元素。

我有一个哈希:

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

4 个答案:

答案 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,但如果这些不可用,那么您必须对其进行修补。

此代码不会尝试处理错误,例如键的数组与散列中的键不匹配。如何处理以及返回的内容留待您了解。

相关问题