TCSGrad
TCSGrad

Reputation: 12118

Why doesn't map! with an if work like I expect?

When I run the following code:

range = [2,3,4,5,6,7,8,9,10]
range.each {|z| print z, " "}
puts "\n"
range.map! {|y| y /= 3 if y % 3 == 0}
range.each {|z| print z, " "}

I get the following output:

2 3 4 5 6 7 8 9 10
nil 1 nil nil 2 nil nil 3 nil

Whereas I'm expecting the second line of output to contain:

2 1 4 5 2 7 8 3 10

What am I doing wrong? Am I misunderstanding the way the map operator and how its associated code block is supposed to work?

Note: I'm learning Ruby after programming extensively in C/C++ for a number of years, and this is the smallest snippet of a non-working Ruby program that I've been stuck in. If required, I can paste the original program out of which I constructed this MWE as well.

Upvotes: 0

Views: 104

Answers (2)

Pavel Strakhov
Pavel Strakhov

Reputation: 40502

Replace with this:

range.map! {|y| y % 3 == 0 ? y / 3 : y}

map uses the value you returned from the block. There is no point in altering temporary y variable.

Upvotes: 3

Mark Rushakoff
Mark Rushakoff

Reputation: 258278

y /= 3 if y % 3 == 0 is a whole expression on its own. When the conditional part evaluates to false, the entire expression evaluates to nil. map! is modifying the array in-place and it doesn't care if the resulting elements are numbers or nil.

One way to rewrite that to get the desired output would be:

range.map! {|y| y % 3 == 0 ? y / 3 : y}

Upvotes: 7

Related Questions