Nob*_*ita 87 ruby hash conditional
假设我尝试访问这样的哈希:
my_hash['key1']['key2']['key3']
Run Code Online (Sandbox Code Playgroud)
如果key1中存在key1,key2和key3,这很好,但是如果,例如key1不存在呢?
然后我会得到NoMethodError: undefined method [] for nil:NilClass.没有人喜欢这样.
到目前为止,我处理这个有条件的事情:
if my_hash['key1'] && my_hash['key1']['key2'] ...
这是否合适,还有其他Rubiest方式吗?
dbe*_*hur 170
有很多方法可以解决这个问题.
如果您使用Ruby 2.3或更高版本,则可以使用dig
my_hash.dig('key1', 'key2', 'key3')
Run Code Online (Sandbox Code Playgroud)
很多人坚持使用普通的红宝石并进行&&防护测试.
您也可以使用stdlib Hash #fetch :
my_hash.fetch('key1', {}).fetch('key2', {}).fetch('key3', nil)
Run Code Online (Sandbox Code Playgroud)
有些人喜欢链接ActiveSupport的#try方法.
my_hash.try(:[], 'key1').try(:[], 'key2').try(:[], 'key3')
Run Code Online (Sandbox Code Playgroud)
其他人使用andand
myhash['key1'].andand['key2'].andand['key3']
Run Code Online (Sandbox Code Playgroud)
有些人认为以自我为中心的nils是一个好主意(尽管如果他们发现你这样做,有人可能会追捕你并折磨你).
class NilClass
def method_missing(*args); nil; end
end
my_hash['key1']['key2']['key3']
Run Code Online (Sandbox Code Playgroud)
您可以使用Enumerable #reduce(或别名注入).
['key1','key2','key3'].reduce(my_hash) {|m,k| m && m[k] }
Run Code Online (Sandbox Code Playgroud)
或者使用嵌套查找方法扩展Hash或仅扩展目标哈希对象
module NestedHashLookup
def nest *keys
keys.reduce(self) {|m,k| m && m[k] }
end
end
my_hash.extend(NestedHashLookup)
my_hash.nest 'key1', 'key2', 'key3'
Run Code Online (Sandbox Code Playgroud)
哦,我们怎么可能忘了,也许单子?
Maybe.new(my_hash)['key1']['key2']['key3']
Run Code Online (Sandbox Code Playgroud)
您也可以使用Object#和.
my_hash['key1'].andand['key2'].andand['key3']
Run Code Online (Sandbox Code Playgroud)
条件my_hash['key1'] && my_hash['key1']['key2']不觉得干.
备择方案:
1)autovivification魔术.从那篇文章:
def autovivifying_hash
Hash.new {|ht,k| ht[k] = autovivifying_hash}
end
Run Code Online (Sandbox Code Playgroud)
然后,用你的例子:
my_hash = autovivifying_hash
my_hash['key1']['key2']['key3']
Run Code Online (Sandbox Code Playgroud)
它类似于Hash.fetch方法,因为它们都以新哈希作为默认值进行操作,但这会将细节移动到创建时间.不可否认,这有点作弊:它永远不会返回'nil'只是一个空的哈希,它是动态创建的.根据您的使用情况,这可能会浪费.
2)利用查找机制抽象出数据结构,并处理幕后未发现的案例.一个简单的例子:
def lookup(model, key, *rest)
v = model[key]
if rest.empty?
v
else
v && lookup(v, *rest)
end
end
#####
lookup(my_hash, 'key1', 'key2', 'key3')
=> nil or value
Run Code Online (Sandbox Code Playgroud)
3)如果你觉得monadic你可以看看这个, 也许吧
| 归档时间: |
|
| 查看次数: |
27033 次 |
| 最近记录: |