1

We're supposed to make an array and puts only even numbers. This is my incorrect code:

my_array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
my_array.each { |num| num % 2 == 0 ? puts num }

It raises this error:

(ruby):1: syntax error, unexpected tIDENTIFIER, expecting keyword_do or '{' or '('
my_array.each { |num| num % 2 == 0 ? puts num }

Correct, functional code:

my_array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
my_array.each { |num| puts num unless num % 2 != 0 }

I want to know why code I wrote wouldn't run, even though I know how to write a working version. Does the problem stem from having puts num in the conditional part of my single line if statement?

sawa
  • 165,429
  • 45
  • 277
  • 381
  • 1
    Best to avoid `num % 2 == 0` to determine if `num` is an even number. `num.even?` and `num.odd?` are cleaner and read better. – Cary Swoveland Jul 13 '18 at 02:21
  • @CarySwoveland thank you - using num.odd? or num.even? works well in this instance! – Enrico Matassa Jul 13 '18 at 02:25
  • 2
    Also, note that `unless num % 2 != 0` is the same as the simpler `if num % 2 == 0`. Whenever you have `if x == 0`, consider `x.zero?` instead. It avoid the common bug `if x = 0` when `x == 0` is intended. (Recent versions of Ruby issue a warning when she encounters `x = 0` and suspectes you meant `x == 0`.) – Cary Swoveland Jul 13 '18 at 02:29

2 Answers2

4

This syntax:

my_array.each { |num| num % 2 == 0 ? puts num }

The ? in this example is a half of a ternary operator, which is basically short hand for a if .. else .. end statement.

The problem with your code is that you are missing half of it, and it does not really apply with your exact structure.

To make it work, it would need to look something similar to this:

my_array.each { |num| (num % 2).zero? ? (puts num) : next } 

You need to add the else side of the statement, which comes after a colon. It is likely not the ideal syntax to use in your example, but can work with the next statement, which in this case does nothing and simply has the control flow continue on to the next iteration.

Here is good answer on SO describing how to use ternary operators in Ruby.

ForeverZer0
  • 2,379
  • 1
  • 24
  • 32
  • Thanks for the reply! I'm having one issue though, which is that I am still receiving an error in this case even when adding " : next " exactly as you did above. Is it not possible to use num in this exact instance with a ternary operator? – Enrico Matassa Jul 12 '18 at 22:57
  • I just got it to run! The closest thing that worked was my_array.each { |num| puts num if num % 2 == 0 } It looks like I have to place "puts num" at the beginning of the argument in order to get it to run. This might not be totally conclusive but it's what I can understand from the syntax at this point. For reference, the above edited answer also works! – Enrico Matassa Jul 12 '18 at 23:00
  • 1
    @EnricoMatassa Made an edit, it seems using the in-line `{ .. }` with a ternary operator is confusing the interpreter. I altered it. – ForeverZer0 Jul 12 '18 at 23:00
  • 1
    I would suggest `array.each { |num| puts num if num % 2 == 0 }`, or better, `puts num if num.even?`. – Cary Swoveland Jul 13 '18 at 03:05
  • That would likely be an improvement. As I stated, a ternary operator is not probably the best choice in this situation. Complexity-wise, they are they same, but for the sake of readability, yours is the better option. The question was asking for the reason their code didn't run, not necessarily what the ideal solution is, which I would personally do something similar to the "correct" answer example. I am old-school, prefer `% 2 == 0` over `even?` for some reason. Just my personal preference. – ForeverZer0 Jul 13 '18 at 03:09
  • 1
    Also `next` serves no purpose here. btw, I too am old-school, but from the days when elementary school pupils were taught to compute square roots with pencil and paper, and I prefer `even?` and `odd?`. – Cary Swoveland Jul 13 '18 at 03:17
  • Cool story. When you write Ruby code, feel free to use `even?` and `odd?` if that's your preference, I won't tell you its wrong. :) – ForeverZer0 Jul 13 '18 at 03:19
3

you can use Integer#even?

> my_array.each { |i| puts i if i.even?}

OR

> puts *my_array.select(&:even?)
Gagan Gami
  • 10,121
  • 1
  • 29
  • 55