如何在此代码中减少或注入工作

时间:2016-09-17 06:46:17

标签: ruby reduce inject hash-of-hashes

在代码大战中找到这个作为解决方案之一。有人可以向我解释" 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)

4 个答案:

答案 0 :(得分:2)

假设我们执行

{ :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会返回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) } rescue default而不是...args.reduce(self) { |acum, key| acum.fetch(key, default) }。见Hash#fetch

答案 1 :(得分:1)

它假定self是一个哈希嵌套,并将args视为一系列键,以深入深入到该哈希嵌套中。

答案 2 :(得分:0)

selfconfig哈希本身。

reduce接受self的参数(因此原始config哈希)。

然后,第一次迭代的accum将被赋予该参数(原始config哈希)。

在每次迭代中,accum将使用args的每个键的(嵌套)值重新分配。

答案 3 :(得分:0)

让我们看一下以下示例。

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
}

输出为HEX值0x777,由Ruby转换为小数1911

在使用args.reduce(self)的示例中,self是作为块的第一个参数传递的初始值,即config哈希本身。数组混合在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},我们将其返回并成为下一次迭代的第一个参数。

迭代2

  • hash包含{:mode=>1911},因为我们在上一次迭代中返回了 newhash
  • key包含:mode;数组的第二项。
  • newhash包含1911;减少迭代完成,这是最终值。