在此代码中如何减少或注入工作
how does reduce or inject work in this code
在 code wars 上找到了这个作为解决方案之一。有人可以向我解释 "args.reduce(self)" 在此代码中的工作原理吗?之后的块是有道理的。
config = { :files => { :mode => 0x777 }, :name => "config" }
class Hash
def get_value( default, *args )
args.empty? ? default : args.reduce(self) { |acum, key| acum.fetch(key) } rescue default
end
end
config.get_value("", :files,:mode)
它假定 self
是一个哈希嵌套,并将 args
视为一个键序列,以便越来越深入地深入到该哈希嵌套中。
假设我们执行
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b, :c)
所以在方法内
default #=> 4
args #=> [:a, :b, :c]
self #=> { :a=>{:b=>{:c=>3 } } }
我们接着执行下面的1:
args.empty? ? default : args.reduce(self) { |acum, key| acum.fetch(key) } rescue default
#=> [:a, :b, :c].empty? ? 4 : [:a, :b, :c].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
# acum.fetch(key) } rescue 4
#=> 3
如果args #=> [:a, :b]
,我们执行如下:
[:a, :b].empty? ? 4 : [:a, :b].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> {:c=>3}
如果 args #=> [:a, :b, :cat]
,则引发 KeyError
异常并且内联 rescue
returns default
:
的值
[:a, :b, :cat].empty? ? 4 : [:a, :b, :cat].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> 4
如果args #=> []
,[].empty?
是true
,那么再次返回default
的值:
[].empty? ? 4 : [].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> 4
幸运的是,我们不再需要像 Ruby 2.3.0 中给我们的 Hash#dig 那样处理这些废话,让我们可以编写以下内容。
class Hash
def get_value( default, *keys )
keys.empty? ? default : dig(*keys) || default
end
end
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b, :c)
#=> 3
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b)
#=> {:c=>3}
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b, :cat)
#=> 4
{ :a=>{:b=>{:c=>3 } } }.get_value(4)
#=> 4
请注意 dig
的默认接收者是 self
。
1 请注意,该代码的作者可以写 ...args.reduce(self) { |acum, key| acum.fetch(key, default) }
而不是 ...args.reduce(self) { |acum, key| acum.fetch(key) } rescue default
。见 Hash#fetch.
self
是 config
散列本身。
reduce
接受一个参数 self
(因此原始 config
散列)。
然后 accum
将在第一次迭代时分配该参数(原始 config
哈希)。
在每次迭代中,accum
将被重新分配 args
的每个键的(嵌套)值。
让我们看看下面的例子。
config = {
:files => { :mode => 0x777 },
:name => "config"
}
[:files, :mode].reduce(config) { |hash, key|
# The value for the current key, which can be another hash.
newhash = hash.fetch(key)
# Log each iteration here to see what's happening.
# p newhash
# Return the value for next iteration.
newhash
}
输出的是十六进制值0x777
,由Ruby转换为十进制1911
。
在您使用 args.reduce(self)
的示例中,self
是作为第一个参数传递给块的初始值,即 config
哈希本身。 Array 混合在 Enumerable 中,这就是 reduce 的来源。更多信息在这里:http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-reduce
对于 reduce 的每次迭代,块变量包含以下值:
迭代 1
hash
包含{ :files => { :mode => 0x777 }, :name => "config" }
;这是 config 哈希本身。
key
包含:files
;数组的第一项。
newhash
包含 {:mode=>1911}
,我们 return 并成为下一次迭代的第一个参数。
迭代 2
hash
包含 {:mode=>1911}
因为我们在上一次迭代中 returned newhash。
key
包含:mode
;数组的第二项。
newhash
包含1911
; reduce 迭代已完成,这是最终值。
在 code wars 上找到了这个作为解决方案之一。有人可以向我解释 "args.reduce(self)" 在此代码中的工作原理吗?之后的块是有道理的。
config = { :files => { :mode => 0x777 }, :name => "config" }
class Hash
def get_value( default, *args )
args.empty? ? default : args.reduce(self) { |acum, key| acum.fetch(key) } rescue default
end
end
config.get_value("", :files,:mode)
它假定 self
是一个哈希嵌套,并将 args
视为一个键序列,以便越来越深入地深入到该哈希嵌套中。
假设我们执行
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b, :c)
所以在方法内
default #=> 4
args #=> [:a, :b, :c]
self #=> { :a=>{:b=>{:c=>3 } } }
我们接着执行下面的1:
args.empty? ? default : args.reduce(self) { |acum, key| acum.fetch(key) } rescue default
#=> [:a, :b, :c].empty? ? 4 : [:a, :b, :c].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
# acum.fetch(key) } rescue 4
#=> 3
如果args #=> [:a, :b]
,我们执行如下:
[:a, :b].empty? ? 4 : [:a, :b].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> {:c=>3}
如果 args #=> [:a, :b, :cat]
,则引发 KeyError
异常并且内联 rescue
returns default
:
[:a, :b, :cat].empty? ? 4 : [:a, :b, :cat].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> 4
如果args #=> []
,[].empty?
是true
,那么再次返回default
的值:
[].empty? ? 4 : [].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> 4
幸运的是,我们不再需要像 Ruby 2.3.0 中给我们的 Hash#dig 那样处理这些废话,让我们可以编写以下内容。
class Hash
def get_value( default, *keys )
keys.empty? ? default : dig(*keys) || default
end
end
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b, :c)
#=> 3
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b)
#=> {:c=>3}
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b, :cat)
#=> 4
{ :a=>{:b=>{:c=>3 } } }.get_value(4)
#=> 4
请注意 dig
的默认接收者是 self
。
1 请注意,该代码的作者可以写 ...args.reduce(self) { |acum, key| acum.fetch(key, default) }
而不是 ...args.reduce(self) { |acum, key| acum.fetch(key) } rescue default
。见 Hash#fetch.
self
是 config
散列本身。
reduce
接受一个参数 self
(因此原始 config
散列)。
然后 accum
将在第一次迭代时分配该参数(原始 config
哈希)。
在每次迭代中,accum
将被重新分配 args
的每个键的(嵌套)值。
让我们看看下面的例子。
config = {
:files => { :mode => 0x777 },
:name => "config"
}
[:files, :mode].reduce(config) { |hash, key|
# The value for the current key, which can be another hash.
newhash = hash.fetch(key)
# Log each iteration here to see what's happening.
# p newhash
# Return the value for next iteration.
newhash
}
输出的是十六进制值0x777
,由Ruby转换为十进制1911
。
在您使用 args.reduce(self)
的示例中,self
是作为第一个参数传递给块的初始值,即 config
哈希本身。 Array 混合在 Enumerable 中,这就是 reduce 的来源。更多信息在这里:http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-reduce
对于 reduce 的每次迭代,块变量包含以下值:
迭代 1
hash
包含{ :files => { :mode => 0x777 }, :name => "config" }
;这是 config 哈希本身。key
包含:files
;数组的第一项。newhash
包含{:mode=>1911}
,我们 return 并成为下一次迭代的第一个参数。
迭代 2
hash
包含{:mode=>1911}
因为我们在上一次迭代中 returned newhash。key
包含:mode
;数组的第二项。newhash
包含1911
; reduce 迭代已完成,这是最终值。