Question

I was trying to do the following in code and not sure how to use the modulus with case when

(1..100).each do |number|
  case number
    when % 3 and % 5
      puts "Hello World"
    when % 3
      puts "Hello"
    when % 5
      puts "World"
    else
      puts number
   end
end

I know I am just missing something dumb, but no idea what that is.

Edit: just changed it to how it would have to work.

Était-ce utile?

La solution

I'd probably write it something like this. It's an old-school thing:

(1..15).each do |number|
  case
  when (number % 3 == 0) && (number % 5 == 0)
    puts "(#{ number }) Hello World"
  when (number % 3 == 0)
    puts "(#{ number }) Hello"
  when (number % 5 == 0)
    puts "(#{ number }) World"
  else
    puts number
  end
end

# >> 1
# >> 2
# >> (3) Hello
# >> 4
# >> (5) World
# >> (6) Hello
# >> 7
# >> 8
# >> (9) Hello
# >> (10) World
# >> 11
# >> (12) Hello
# >> 13
# >> 14
# >> (15) Hello World

Here's how I'd really write it:

(1..15).each do |number|
  val = case
        when (number % 3 == 0) && (number % 5 == 0)
          "Hello World"
        when (number % 3 == 0)
          "Hello"
        when (number % 5 == 0)
          "World"
        else
          number
        end

  puts val
end

This is cleaner and even more readable. While it's possible to use case 0, the tests for each when become less easily understood, which is a prime consideration when we write code. We write for at least two people, ourselves at the moment, and for whoever is maintaining it in the future. It needs to make sense at all times, so the more obvious and clean the code is, the faster it'll enter the brain when it's read in a couple years, reducing debugging time and the work-load on the future you.

Autres conseils

I believe case is for the situations where you need to compare the result of one expression to multiple values.

Here you have several expressions number % 3, number % 5 and number % 15 compared to one value 0. I would suggest using if-elsif-else here:

if number % 15 == 0
  puts 'Hello World'
elsif number % 3 == 0
  puts 'Hello'
elsif number % 5 == 0
  puts 'World'
else
  puts number
end

Or consider reversing the idea of this comparison and making 0 the expression itself:

case 0
when number % 15
  puts "Hello World"
when number % 3
  puts "Hello"
when number % 5
  puts "World"
else
  puts number
end

I prefer the former solution. More straightforward and one less line.

p.s. I personally think that expressionless case-s are ugly :)

The below will work :

(1..15).each do |number|
  case 0
    when number%3 + number%5
      puts "Hello World"
    when number % 3
      puts "Hello"
    when number % 5
      puts "World"
    else
      puts number
   end
end

# >> 1
# >> 2
# >> Hello
# >> 4
# ...
# >> 13
# >> 14
# >> Hello World

FYI: Moved the third condition to be the first - otherwise it would never be reached.

(1..100).each do |number|
  puts case number
  when ->x{x.%(3).zero? and x.%(5).zero?}
    "Hello World"
  when ->x{x.%(3).zero?}
    "Hello"
  when ->x{x.%(5).zero?}
    "World"
  else
    number
  end
end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top