h = {
data: {
user: {
value: "John Doe"
}
}
}
要为嵌套哈希值赋值,我们可以使用
h[:data][:user][:value] = "Bob"
但是,如果缺少中间的任何部分,则会导致错误。
就像是
h.dig(:data, :user, :value) = "Bob"
不起作用,因为还没有Hash#dig=
可用。
为了安全地分配价值,我们可以做到
h.dig(:data, :user)&.[]=(:value, "Bob") # or equivalently
h.dig(:data, :user)&.store(:value, "Bob")
但有更好的方法吗?
它并非没有它的警告(如果你从其他地方收到哈希值,它就不起作用),但一个常见的解决方案是:
hash = Hash.new {|h,k| h[k] = h.class.new(&h.default_proc) }
hash[:data][:user][:value] = "Bob"
p hash
# => { :data => { :user => { :value => "Bob" } } }
我找到了一个简单的解决方案来设置嵌套哈希的值,即使父键缺失,即使哈希已经存在。鉴于:
x = { gojira: { guitar: { joe: 'charvel' } } }
假设您想要包含马里奥的鼓来导致:
x = { gojira: { guitar: { joe: 'charvel' }, drum: { mario: 'tama' } } }
我结束了猴子修补哈希:
class Hash
# ensures nested hash from keys, and sets final key to value
# keys: Array of Symbol|String
# value: any
def nested_set(keys, value)
raise "DEBUG: nested_set keys must be an Array" unless keys.is_a?(Array)
final_key = keys.pop
return unless valid_key?(final_key)
position = self
for key in keys
return unless valid_key?(key)
position[key] = {} unless position[key].is_a?(Hash)
position = position[key]
end
position[final_key] = value
end
private
# returns true if key is valid
def valid_key?(key)
return true if key.is_a?(Symbol) || key.is_a?(String)
raise "DEBUG: nested_set invalid key: #{key} (#{key.class})"
end
end
用法:
x.nested_set([:instrument, :drum, :mario], 'tama')
用于您的示例:
h.nested_set([:data, :user, :value], 'Bob')
我错过了任何警告?在不牺牲可读性的情况下编写代码的更好方法是什么?
有趣的一个:
def dig_set(obj, keys, value)
if keys.length == 1
obj[keys.first] = value
else
dig_set(obj[keys.first], keys.slice(1..-1), value)
end
end
如果没有[]
或[]=
方法,将提出异常。