为什么红宝石的注射不正确总结?

时间:2013-10-13 13:58:43

标签: ruby enumerators

我没有从Integer中的以下猴子修补方法得到正确的结果:

def harm
  1 + (2..self).inject{|sum, x| sum + 1/x.to_r}
end

2.harm #=> 3

它应该返回3/2而不是,我的错误在哪里?

3 个答案:

答案 0 :(得分:4)

这里有两个问题:

  1. 当你在一个封闭的范围内迭代时,例如2..2,实际上什么也没发生:

    (0..0).inject(){|s, x| s+= 99 }
    # => 0
    

    这就是为什么你得到3,因为1 + 23

  2. 如果你没有将参数传递给inject,它会使用你传递给迭代器的第一个值作为起始备忘录,即2

    (2..2).inject(){|s, x| s+= 99 }
    #=> 2
    

    输入0可以获得实际的迭代:

    (2..2).inject(0){|s, x| s+= 99 }
    #=> 99
    
  3. 请在您的方法中尝试使用此方法:

    1 + (2..self).inject(0){|sum, x| sum + 1/x.to_r}  
    

    独立:

    1 + (2..2).inject(0){|sum, x| sum + 1/x.to_r}  
    #=> 3/2
    

答案 1 :(得分:2)

以下是提示(您需要将初始值传递给inject方法):

def harm
  1 + (2..2).inject(0){|sum, x| sum + 1/x.to_r}
end

harm # => (3/2)

Enumerable#inject的文档:

  

如果指定一个块,那么对于枚举中的每个元素,块将传递一个累加器值(memo)和元素。如果指定了符号,则集合中的每个元素都将传递给命名的备忘录方法。在任何一种情况下,结果都将成为备忘录的新值。在迭代结束时,memo的最终值是方法的返回值。

     

如果没有明确指定备忘录的初始值,那么集合的第一个元素将用作备忘录的初始值。

答案 2 :(得分:1)

在我决定花费你的问题的1分钟内,我无法意识到你的代码有什么问题。但是我能够编写这种类似于你想做的事情的方法:

class Integer
  def harm
    return 0 if self == 0
    return -(-self).harm if self < 0
    ( 1 .. self ).map { |n| Rational 1, n }.reduce :+
  end
end

0.harm #=> 0
2.harm #=> 3/2
7.harm #=> 363/140
-2.harm #=> (-3/2)

但请注意,对于大量数据,这种高度可读的代码效率低下,因为它在执行求和之前在内存中准备数组。