SSDong
SSDong

Reputation: 145

Ruby enumerator with chaining

I am a newbie of Ruby and I don't quite understand the following code.

n = [1,2,3]
n.map!.select{|x| x+=1}
puts n.inspect

will give me

[nil, nil, nil]

I know that n.map! will give me an enumerator but I don't get it why calling select on it will make n becomes nil. I know that map! will modify the original object, I just don't understand how that's achieved.

Update:

I tried n.map!.select {|x| true}, n is still [nil, nil, nil]

I appreciate your help! Thanks!

Upvotes: 1

Views: 81

Answers (2)

songyy
songyy

Reputation: 4573

In the comments, it says:

It's to do with the in-place modification of map!

that's true. Let me make it clearer here:

In the definition of Array#map!, it says:

map! {|item| block } → ary click to toggle source
map! → Enumerator

Invokes the given block once for each element of self, replacing the element with the value returned by the block

So:

Example 1

[58] pry(main)> a = [1,2,3] => [1, 2, 3] [60] pry(main)> e = a.map! => #<Enumerator: ...> [61] pry(main)> e.each {|n| n + 1} => [2, 3, 4] [62] pry(main)> a => [2, 3, 4]

However:

Example 2

[71] pry(main)> a = [1,2,3] => [1, 2, 3] [72] pry(main)> e = a.map! => #<Enumerator: ...> [73] pry(main)> e.next => 1 [74] pry(main)> a => [1, 2, 3] [75] pry(main)> e.peek => 2 [76] pry(main)> a => [nil, 2, 3]

I think this due to Enumerator#each call takes a block, and that would be the return value from example 1; but when Enumerator#next is called (same goes to Enumerator.to_a), it cannot evaluate the block, therefore, returning nil.

Upvotes: 0

Finks
Finks

Reputation: 1681

It's because the select method is used for selection. It returns the element that satisfies the condition you placed in your block. In your case, you didn't put any condition so it returned nil

e.g. You want to do something like this:

n = [1,2,3]
n.select { |num| num < 3 }  

#=> This should return
#=> [1,2]

Upvotes: 4

Related Questions