繁体   English   中英

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

[英]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

之所以起作用,是因为如果对于ka某些元素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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM