Reputation: 35522
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?
Upvotes: 2
Views: 115
Reputation: 12578
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.
Upvotes: 1
Reputation: 3388
There are two problems here:
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
.
If you do not pass an argument into inject
, it uses the first value you pass into the iterator as the starting memo, i.e. 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
Upvotes: 4
Reputation: 118271
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.
Upvotes: 2