brslv brslv - 7 months ago 39
Ruby Question

Map on collection returns nil

I'm currently learning ruby and playing around with collections. I'm now stuck on a problem and need some help to understand why something works this way.

So, we have a simple array:

arr = ["cat", "dog", "pig", "goat"]

Now, I want to make every second elem uppercased and reversed. The first thing that I thought was the ternary:

modified = do |el, idx|
((idx + 1) % 2 == 0) ? el.upcase.reverse : el

No big deal. But I played around and came up with another solution.

modified = do |el, idx|
el.upcase.reverse if (idx + 1) % 2 == 0
el unless (idx + 1) % 2 == 0

It seems correct to me, but not to the interpreter.

With the ternary I get the result:

["cat", "GOD", "pig", "TAOG"]

But with the later approach:

["cat", nil, "pig", nil]

Can somebody, please, explain why the later doesn't work (it puts nill on every second elem)?

If I do it with regular if-else, it works again.

modified = do |el, idx|
if (idx + 1) % 2 == 0

How the regular if is different than the one-liners?

Thanks in advance!


Array#map would use the return value of the block passed in parameter to build the new array.

Since you are not using any return statement, it will always be the last expression evaluated.

In your first and third solutions, you always "hit" el or el.upcase.reverse

In your second solution, when (idx + 1) % 2 == 0, you are not doing anything, so you return simply nil.

Hope this helps.

Note : look at Integer#odd? and Integer#even?