简体   繁体   中英

Why ruby's inject doesn't sum correctly?

I'm not getting correct results from the following monkey-patching method in Integer:

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

2.harm #=> 3

it should return 3/2 instead, where is my mistake?

There are two problems here:

  1. When you iterate across a closed range, such as 2..2 , nothing actually happens:

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

    Which is why you get 3 , as 1 + 2 is 3 .

  2. If you do not pass an argument into inject , it uses the first value you pass into the iterator as the starting memo, ie 2 :

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

    Putting in a 0 gets you an actual iteration:

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

So try this instead in your method:

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

Standalone:

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

Here is the tip(you need to pass the initial value to the inject method):

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

harm # => (3/2)

Documentation of Enumerable#inject :

If you specify a block, then for each element in enum the block is passed an accumulator value (memo) and the element. If you specify a symbol instead, then each element in the collection will be passed to the named method of memo. In either case, the result becomes the new value for memo. At the end of the iteration, the final value of memo is the return value for the method.

If you do not explicitly specify an initial value for memo, then the first element of collection is used as the initial value of memo.

In the 1 minute of time that I decided to spend over your question, I was unable to realize what's wrong with your code. But I was able to write this method that does something similar to what you want to do:

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)

Note, though, that for large number, this highly readable code becomes inefficient, as it prepares the array in the memory before performing the summation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM