Почему инъекция рубина не суммируется правильно?

Я не получаю правильные результаты от следующего метода исправления обезьян в Integer:

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

2.harm #=> 3

вместо этого он должен вернуть 3/2, где моя ошибка?

3 ответа

Здесь есть две проблемы:

  1. Когда вы перебираете закрытый диапазон, такой как 2..2на самом деле ничего не происходит

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

    Вот почему вы получаете 3, как 1 + 2 является 3,

  2. Если вы не передадите аргумент в inject, он использует первое значение, которое вы передаете в итератор, как начальную заметку, т.е. 2:

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

    Установка 0 дает вам реальную итерацию:

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

Так что попробуйте это вместо этого в вашем методе:

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

Вот совет (вам нужно передать начальное значение в inject метод):

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

harm # => (3/2)

Документация Enumerable#inject:

Если вы указываете блок, то для каждого элемента в перечислении блоку передается значение аккумулятора (памятка) и элемент. Если вместо этого указать символ, то каждый элемент в коллекции будет передан в именованный метод memo. В любом случае результат становится новым значением для памятки. В конце итерации конечное значение memo - это возвращаемое значение для метода.

Если вы явно не указали начальное значение для памятки, то первый элемент коллекции используется в качестве начального значения памятки.

За 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)

Тем не менее, обратите внимание, что для большого числа этот хорошо читаемый код становится неэффективным, так как он подготавливает массив в памяти перед выполнением суммирования.

Другие вопросы по тегам