0

I've been going through the exercises at Ruby Monk and I'm having trouble deciphering one of the example solutions.

The problem (from this page) was:

Write a method that counts the number of elements of the array that is being passed in, only if the index of the number 42 in the one-dimensional representation of the array is 5.

My solution, which worked fine, was:

def zen(array)
  converted_array = array.flatten.compact
  converted_array.count if converted_array.index(42) == 5
end

Their solution was:

def zen(array)
  converted = array.compact.flatten
  converted.index(42) == 5 ? converted.count : nil
end

I understand everthing to the left of the : in the second line of the method but after that I can't figure it out. I thought that compact removes all nil values from an array?

SoSimple
  • 701
  • 9
  • 30
  • `:` goes with the `?`, it's a single operator. It's a shortcut: `a?b:c` is `if(a) then b else c`. – Mat May 03 '15 at 10:40
  • http://stackoverflow.com/questions/4252936/how-do-i-use-the-conditional-operator-in-ruby – Mat May 03 '15 at 10:40
  • @Mat, thanks so much for clarifying that. If you it in an answer I'll be happy to accept it. – SoSimple May 03 '15 at 10:46

1 Answers1

3

The ?...: is known as the Ternary operator. Let's say that we wanted to set a variable x equal to AM or PM based on the current time. In plain language we might say:

x='AM' if time < '12:00' but x='PM' if time > '12:00'

Clearly, though, that's not valid Ruby (or anything else for that matter!) We can do the same thing with the ternary operator, simplifying what would otherwise become two conditionals:

x = time < '12:00' ? 'AM' : 'PM'

Knowing that this is how it works, we can now understand the last line of your zen function. Realizing it is the last line is very important...

converted.index(42) == 5 ? converted.count : nil

You are correct that compact will remove nils, but this isn't looking to see if there are nils inside of the resulting array. In stead, this is checking to see if element 42 in that array is 5. If it is, the entire function returns converted.count. If it is not equal to 5, the entire function returns nil.

Why? Because the evaluated value of the last line of a function in Ruby is returned as it's return value. If you think about it, this is true for the return statement as well, since it evaluates to whatever you put to its right!

David Hoelzer
  • 15,862
  • 4
  • 48
  • 67
  • Thanks so much for explaining this. It's super helpful! – SoSimple May 03 '15 at 10:49
  • Your example is exactly equivalent to `x = if time < '12:00' then 'AM' else 'PM' end`. In general, unlike other languages, where `if` is a statement and the conditional operator is an expression, there is rarely a need to use the conditional operator in Ruby, since `if` is also an expression (in fact, there are no statements in Ruby). Really, the only difference is brevity (which is not universally a good thing) and precedence, and the precedence of the conditional operator has tripped up quite a few programmers as evidenced by questions about it here on SO. – Jörg W Mittag May 03 '15 at 12:10
  • Note: this is not criticism of your answer. – Jörg W Mittag May 03 '15 at 12:11
  • @JörgWMittag Very true. :) I was just trying to be clear for someone unfamiliar with ternary operations. Perhaps your example could be edited in as an example of how it's a shorthand for the if...then...else...end. – David Hoelzer May 03 '15 at 12:48
  • Feel free to steal ;-) Oh, and thanks for your reply, it reminded me I forgot to upvote. – Jörg W Mittag May 03 '15 at 12:50