Nil class using Ruby injection

I am new to Ruby and am having a weird issue with the injection method.

When I do this:

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

the result is 10, as expected. But when I do

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

I get an error message:

 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 

I really don't understand why the (apparently) count in the second example is zero, but not the first. Anyway, how would I count evens from 1 to 10 with an injection?

+7
ruby
source share
2 answers

The expression count + 1 if (x%2 == 0) returns nil when the condition is not true, for which count set, because the nature of the injection method.

You can fix this by returning count + 1 when it is an even number and just count when it is not:

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

A completely different solution is to use select to select even numbers and use the Array#length method to count them.

 (1..10).select { |x| x % 2 == 0 }.length 
+14
source share

As yjerem already pointed yjerem , count + 1 if (x%2 == 0) will evaluate to nil when x is odd. And here's the problem: the nil value will be assigned to count , so the next iteration will be nil + 1 , which caused an error.

It's important to understand how injection works (copy of ruby-doc )

enum.inject (initial) {| memo, obj | block} => obj

enum.inject {| memo, obj | block} => obj

Combines the elements of an enumeration, applying a block to the value of the accumulator (memo) and each element in turn. At each step, memo is set to the value returned by the block. The first form allows you to specify the initial value for the memo. The second form uses the first element of the collection as the initial value (and skips this element during iteration).

The rule will not allow you to avoid such an error: the unit should always return the same type of value as the battery. If in your example the block returns type nil when x%2==0 , if false .

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

+3
source share

All Articles