Fizzbuzz switch statement

343 views Asked by At

Long question but I think it is odd. I was playing around with ruby switch statements. Created a little fizzbuzz function to practice.

Initially created the code like this

def fizzbuzz(start_num, end_num)
    fizzbuzz = []
    (start_num..end_num).each do |x|
        if x % 3 == 0 && x % 5 != 0
            fizzbuzz << "fizz"
        elsif x % 5 == 0 && x % 3 != 0
            fizzbuzz << "buzz"
        elsif (x % 3 == 0 && x % 5 == 0) 
            fizzbuzz << "fizzbuzz"
        else
            fizzbuzz << x.to_s
        end
    end
    fizzbuzz 
end 

Works as expected. Then wanted to play with a switch statement. So I tried:

def fizzbuzz(start_num, end_num)
fizzbuzz = []
(start_num..end_num).each do |x|
    case x
    when x % 3 == 0 
        fizzbuzz << "fizz"
    when x % 5 == 0 
        fizzbuzz << "buzz"
    when (x % 3 == 0 && x % 5 == 0) 
        fizzbuzz << "fizzbuzz"
    else
        fizzbuzz << x.to_s
    end
end
fizzbuzz 

end

This time the code only prints out the number converted to a string. Then mistakenly I tried to add && to the end of every when statement like so

def fizzbuzz(start_num, end_num)
    fizzbuzz = []
    (start_num..end_num).each do |x|
        case x
        when x % 3 == 0 &&
            fizzbuzz << "fizz"
        when x % 5 == 0 &&
            fizzbuzz << "buzz"
        when (x % 3 == 0 && x % 5 == 0) &&
            fizzbuzz << "fizzbuzz"
        else
            fizzbuzz << x.to_s
        end
    end
    fizzbuzz 
end 

Interestingly this prints out the correct result. It is probably a trivial answer, but does anyone know why this is the case? It seems rather odd to me.

2

There are 2 answers

0
Dave Newton On BEST ANSWER

The when statements are doing a logical &&.

This has the side effect of concatenating your output when the condition is true.

The question you're actually asking, based on your comment, is what's going on with the when statements not seeming to work. The problem is that you wrote case x, which is evaluating x on-the-spot and comparing it to the when expressions.

Instead, use a "naked case", e.g.,

case
when (x % 3) == 0
  # etc

Note also that this could be wrapped up a bit tighter, e.g.,

def fizzbuzz(start_num, end_num)
  (start_num..end_num).collect do |x|
    case
      when (x % 3) == 0
        "fizz"
      when (x % 5) == 0
        "buzz"
      when (x % 3 == 0 && x % 5 == 0)
        "fizzbuzz"
      else
        x.to_s
    end
  end
end
2
Yu Hao On

For the last piece of code, let's see one when condition in detail:

when x % 3 == 0 &&
    fizzbuzz << "fizz"

Despite the indentation, it's equivalent to:

when x % 3 == 0 && fizzbuzz << "fizz"

Remember that && is short-circuit. The && expression returns its first argument if it is false. Otherwise, its second argument is evaluated and returned as the result.

So if x % 3 == 0 is false, then fizzbuzz << "fizz" is not executed. If x % 3 == 0 is true, fizzbuzz << "fizz" is executed. Exactly what is expected.