Нулевой класс при использовании инъекции Ruby - PullRequest
7 голосов
/ 24 июля 2010

Я новичок в Ruby, и у меня странная проблема с методом инъекции.

Когда я делаю:

(1..10).inject(0) {|count,x| count + 1}

результат равен 10, как и ожидалось. Но когда я делаю

(1..10).inject(0) {|count,x| count + 1 if (x%2 == 0)}

Я получаю ошибку:

NoMethodError: undefined method `+' for nil:NilClass
    from (irb):43
    from (irb):43:in `inject'
    from (irb):43:in `each'
    from (irb):43:in `inject'
    from (irb):43

Я не очень понимаю, почему (по-видимому) счет равен нулю во втором примере, а не в первом. В любом случае, как бы я посчитал чётные числа от 1 до 10, используя инъекцию?

Ответы [ 2 ]

14 голосов
/ 24 июля 2010

Выражение count + 1 if (x%2 == 0) возвращает nil, когда условие не выполняется, для которого count устанавливается, потому что такова природа метода ввода.

Вы можете исправить это, вернув count + 1, когда это четное число, и просто count, когда это не так:

(1..10).inject(0) { |count,x| x % 2 == 0 ? count + 1 : count }

Совершенно другое решение - использовать select для выбора четных чисел и использовать метод Array#length для их подсчета.

(1..10).select { |x| x % 2 == 0 }.length
3 голосов
/ 24 июля 2010

Как уже указывалось yjerem, count + 1 if (x%2 == 0) будет оцениваться как nil, если x нечетно.И здесь возникает проблема: значение nil будет присвоено count, поэтому следующая итерация будет nil + 1, что вызвало сообщение об ошибке.

Важно понимать, как работает инъекция (копия из ruby-doc )

enum.inject (initial) {|памятка, объект |block} => obj

enum.inject {|памятка, объект |block} => obj

Объединяет элементы enum, применяя блок к значению аккумулятора (памятке) и к каждому элементу по очереди.На каждом шаге memo устанавливается значение, возвращаемое блоком.Первая форма позволяет вам ввести начальное значение для памятки.Вторая форма использует первый элемент коллекции в качестве начального значения (и пропускает этот элемент во время итерации).

Правило защитит вас от ошибок такого рода: блок должен всегда возвращать значение того же типа, что и значение аккумулятора.В вашем примере блок вернет тип nil при x%2==0, если false.

(1..10).inject(0) {|count,x| count + 1 if (x%2 == 0)}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...