Ruby Convert If Statements to Case - ruby

Is it possible to use a case statement to replace these if statements?
if (a%3 == 0) then puts "%3"
elsif (a%4 == 0) then puts "%4"
elsif (a%7 == 0 && a%13 == 0) then puts "%%"

case
when (a % 3).zero? then puts "%3"
when (a % 4).zero? then puts "%4"
when (a % 7).zero? && (a % 13).zero? then puts "%%"
end

Sure:
case
when (a%3 == 0) then puts "%3"
when (a%4 == 0) then puts "%4"
when (a%7 == 0 && a%13 == 0) then puts "%%"
end
It isn't much better, is it? ;-)

puts [3,4,91,10].collect do |a|
case 0
when a % 3 then
"%3"
when a % 4 then
"%4"
when a % 91 then
"%%"
end
end
You should be able to copy that right into irb to see it work. Please forgive the slight 7*13 = 91 hack, but if you're working with actual modulos they should be equivalent.

Using Proc#===
def multiple_of( factor )
lambda{ |number| number.modulo( factor ).zero? }
end
case a
when multiple_of( 3 ): puts( "%3" )
when multiple_of( 4 ): puts( "%4" )
when multiple_of( 7*13 ): puts( "%%" )
end

(a%7 == 0 && a%13 == 0) is equal to (a%7*13 == 0).
in ruby, you can make 1-line if-else statement use && and ||.
puts (a%3 == 0)&&"%3"||(a%4 == 0)&&"%4"||(a%(7*13) == 0)&&"%%"||""
or
log = (a%3 == 0)&&"%3"||(a%4 == 0)&&"%4"||(a%(7*13) == 0)&&"%%"
puts log if log
it's looks agly but short.

Related

Solving foobar in Ruby?

So far I have been able to get the numbers to print properly but I don't know how to loop them.
puts "Please enter a number"
val1 = gets.to_i
val2 = val1 % 3
val3 = val1 % 5
def ordinal(a,b,c)
if b == 0 && c == 0
return "foobar"
elsif b == 0
return "foo"
elsif c == 0
return "bar"
else
return a
end
end
val5 = ordinal(val1,val2,val3)
puts "#{val5}"
I also made a loop that works but it won't recognize strings.
n = 0
x = gets.to_i
while n != x
puts "#{n}"
n = n + 1
end
How do I combine my method and loop? Or is there any other way to solve this? But I would prefer if you solve it using my code IF its any good off course so that I can understand it better.
As par your comments, the loop part is easy when leveraging Integer#times.
This is what you have that works for you:
puts "Please enter a number"
val1 = gets.to_i
val2 = val1 % 3
val3 = val1 % 5
def ordinal(a,b,c)
if b == 0 && c == 0
return "footer"
elsif b == 0
return "foo"
elsif c == 0
return "bar"
else
return a
end
end
val5 = ordinal(val1,val2,val3)
puts "#{val5}"
Right now you're just running through the final number. Try using the Integer#times to run a loop up to the number...:
puts "Please enter a number"
num = gets.to_i
num.times do |a|
a += 1 # counting is done from 0 to n-1
b = a % 3
c = a % 5
if b == 0 && c == 0
print "foobar "
elsif b == 0
print "foo "
elsif c == 0
print "bar "
else
print "#{a} "
end
end
print "\n"
Personally I would probably have written this a bit differently, but I guess it's sound enough.
I would probably write something messy because I hate long if...else statements...:
def foo_bar n
n.times {|i| i+=1; print( (i%15==0 && "FooBar ") || (i%3==0 && "Foo ") || (i%5 ==0 && "Bar ") || ("#{i} ") ) }
print "\n"
end
puts "Enter number:"
foo_bar gets.to_i
You can do this too:
def foobar n
n.times do |i|
i += 1
num = ""
num << "Foo" if i % 3 == 0
num << "Bar" if i % 5 == 0
num = i.to_s if num == ""
puts num
end
end
foobar 15
The logic is simpler than Myst's.
You don't need to test if it's a factor of 15.
Output:
1
2
Foo
4
Bar
Foo
7
8
Foo
Bar
11
Foo
13
14
FooBar
=> 15

Ruby FIzz-buzz can't push numbers to an array

So, as you can see, I'm not well versed in Ruby so it helps if you keep your responses primitive, instead of using short cuts.
I am able to get my fizz-buzz to work in the first example, I added the absolute method to handle negative input and used variables to easily accommodate changing 3 and 5 to other numbers. But, I can't push the results to an array, I just get '1' as a result. Does anyone see where I went wrong?
# not array - works
class Fixnum
define_method(:fizz_buzz) do
fizz = 3
buzz = 5
1.upto(self.abs) do |i|
if (i % fizz == 0) && (i % buzz == 0)
puts "fizz-buzz"
elsif (i % fizz == 0)
puts "fizz"
elsif (i % buzz == 0)
puts "buzz"
else
puts i
end
end
end
end
# push to array - doesn't work
class Fixnum
define_method(:fizz_buzz) do
fizz = 3
buzz = 5
array = []
1.upto(self.abs) do |i|
if (i % fizz == 0) && (i % buzz == 0)
array.push("fizz-buzz")
elsif (i % fizz == 0)
array.push("fizz")
elsif (i % buzz == 0)
array.push("buzz")
else
array.push(i)
end
end
end
end
=> 1
WW
You need to return your array at the end of the function.
class Fixnum
define_method(:fizz_buzz) do
fizz = 3
buzz = 5
array = []
1.upto(self.abs) do |i|
if (i % fizz == 0) && (i % buzz == 0)
array.push("fizz-buzz")
elsif (i % fizz == 0)
array.push("fizz")
elsif (i % buzz == 0)
array.push("buzz")
else
array.push(i)
end
end
array
end
end
In ruby, the last line in the function is used as your return value. When you call 1.upto it runs the given block the specified number of times and then returns the 1. Adding array to the end makes it so it will return the array.

Fizzbuzz switch statement

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.
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
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.

Give an if statement a variable in Ruby

I have this if statement:
if value_n_in_f > 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x+#{value_n_in_f}"
elsif value_n_in_f == 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x"
elsif value_n_in_f < 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x#{value_n_in_f}"
elsif value_n_in_f > 0 && value_m_in_f == 1
puts "I: f(x)=x+#{value_n_in_f}"
elsif value_n_in_f == 0 && value_m_in_f == 1
puts "I: f(x)=x"
elsif value_n_in_f < 0 && value_m_in_f == 1
puts "I: f(x)=x#{value_n_in_f}"
end`
I have to use this statement really often in other statements and it makes my code unnecessarily long. Obviously if_for_f=if ....... end won't work. Is there any other way?
Here's an example what I want it to look like:
puts "Now we insert #{value_of_x} in #{if_for_f}"
Is there any way I can do something like this? Note that I am absolutly new to this.
Thanks in advance,
Kaiton
can't I just def a function with its function to run this case
statement and call it then when I need it it?
Of course:
def do_stuff(m, n)
if m == 1
if n > 0 then "I: f(x)=x+#{n}"
elsif n == 0 then "I: f(x)=x"
elsif n < 0 then "I: f(x)=x#{n}"
end
else
if n > 0 then "I: f(x)=#{m}x+#{n}"
elsif n == 0 then "I: f(x)=#{m}x"
elsif n < 0 then "I: f(x)=#{m}x#{n}"
end
end
end
puts do_stuff(1, 1) #I: f(x)=x+1
Or, if compactness is the goal, we can get to this:
def do_stuff(m, n)
if m == 1
n == 0 ? "I: f(x)=x" : "I: f(x)=x#{sprintf("%+d", n)}"
else
n == 0 ? "I: f(x)=#{m}x" : "I: f(x)=#{m}x#{sprintf("%+d", n)}"
end
end
...and then a one liner:
def do_stuff(m, n)
(m == 1) ? (n == 0 ? "I: f(x)=x" : "I: f(x)=x#{sprintf("%+d", n)}") : (n == 0 ? "I: f(x)=#{m}x" : "I: f(x)=#{m}x#{sprintf("%+d", n)}")
end
end
But your methodology has some problems with zeros and -1:
def do_stuff(value_m_in_f, value_n_in_f)
if value_n_in_f > 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x+#{value_n_in_f}"
elsif value_n_in_f == 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x"
elsif value_n_in_f < 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x#{value_n_in_f}"
elsif value_n_in_f > 0 && value_m_in_f == 1
puts "I: f(x)=x+#{value_n_in_f}"
elsif value_n_in_f == 0 && value_m_in_f == 1
puts "I: f(x)=x"
elsif value_n_in_f < 0 && value_m_in_f == 1
puts "I: f(x)=x#{value_n_in_f}"
end
end
do_stuff(1, 0)
do_stuff(1,-1)
do_stuff(1, 1)
do_stuff(0,-1)
do_stuff(0, 0)
do_stuff(-1, 1)
--output:--
I: f(x)=x
I: f(x)=x-1
I: f(x)=x+1
I: f(x)=0x-1 #<---HERE
I: f(x)=0x #<---HERE
I: f(x)=-1x+1 #<---HERE
So let's fix that:
def get_line_equ(m, b)
constant = (b == 0) ? "" : sprintf("%+d", b) # 2 => "+2"
case m
when 0
xterm = ""
constant = b
when 1
xterm = "x"
when -1
xterm = "-x"
else
xterm = "#{m}x"
end
"I: f(x)=#{xterm}#{constant}"
end
puts get_line_equ(0, 0)
puts get_line_equ(0, -1)
puts get_line_equ(0, 1)
puts get_line_equ(1, 0)
puts get_line_equ(1,-1)
puts get_line_equ(1, 1)
puts get_line_equ(-1, 0)
puts get_line_equ(-1, -1)
puts get_line_equ(-1, 1)
puts get_line_equ(2, 0)
puts get_line_equ(2, -1)
puts get_line_equ(2, 1)
--output:--
I: f(x)=0
I: f(x)=-1
I: f(x)=1
I: f(x)=x
I: f(x)=x-1
I: f(x)=x+1
I: f(x)=-x
I: f(x)=-x-1
I: f(x)=-x+1
I: f(x)=2x
I: f(x)=2x-1
I: f(x)=2x+1
Better?
spoiler:
The final def is not as efficient as it could be: the first line should be removed and copied to each of the when branches--except for the first.
In response to comment:
def my_sprintf(str, *numbers)
str.gsub(/% .*? [df]/x) do |match| #Looks for %...d or %...f sequences
puts match
end
end
my_sprintf("The answer is: %+d or %+d", -2, 3)
--output:--
%+d
%+d
Next:
def my_sprintf(str, *numbers)
str.gsub(/% .*? [df]/x) do |format_sequ|
number_as_str = numbers.shift.to_s
p number_as_str
if format_sequ[1] == "+" and number_as_str[0] != "-"
"+#{number_as_str}"
else
number_as_str
end
end
end
puts my_sprintf("The answer is: %+d or %+d.", -2, 3)
--output:--
"-2"
"3"
The answer is: -2 or +3.
Here's a more compact way to write your case statement. Recall that a <=> b => -1 if a < b, a <=> b => 0 if a == b and a <=> b => -1 if a > b.
"I: f(x)=" +
case [value_n_in_f <=> 0, value_m_in_f == 1]
when [ 1,false] then "#{value_m_in_f}x+#{value_n_in_f}"
when [ 0,false] then "#{value_m_in_f}x"
when [-1,false] then "#{value_m_in_f}x#{value_n_in_f}"
when [ 1,true] then "x+#{value_n_in_f}"
when [ 0,true] then "x"
when [-1,true] then "x#{value_n_in_f}"
end
If you wish to demonstrate how the string is built, you could do something like this (with value_n_in_f and value_m_in_f renamed intercept and slope, respectively):
"I: f(x)=" +
case
when slope.zero?
intercept.zero? ? "0" : "#{intercept}"
else
case slope.to_f
when 1.0 then ""
when -1.0 then "-"
else "#{slope}"
end + "x" +
case intercept <=> 0
when 0 then ""
when -1 then "#{intercept}"
else "+#{intercept}"
end
end
Note that this permits slope < 0, which is not part of the specification. I tested this for various combinations of intercept and slope:
intercept slope string
-2.1 4 I: f(x)=4x-2.1
-2.1 -2.2 I: f(x)=-2.2x-2.1
-2.1 0 I: f(x)=-2.1
-2.1 0.0 I: f(x)=-2.1
-2.1 -1 I: f(x)=-x-2.1
-2.1 1.0 I: f(x)=x-2.1
0 4 I: f(x)=4x
0 -2.2 I: f(x)=-2.2x
0 0 I: f(x)=0
0 0.0 I: f(x)=0
0 -1 I: f(x)=-x
0 1.0 I: f(x)=x
0.0 4 I: f(x)=4x
0.0 -2.2 I: f(x)=-2.2x
0.0 0 I: f(x)=0
0.0 0.0 I: f(x)=0
0.0 -1 I: f(x)=-x
0.0 1.0 I: f(x)=x
3 4 I: f(x)=4x+3
3 -2.2 I: f(x)=-2.2x+3
3 0 I: f(x)=3
3 0.0 I: f(x)=3
3 -1 I: f(x)=-x+3
3 1.0 I: f(x)=x+3
A couple of things here: you can put "puts" before the whole if/elsif block and avoid having puts on every line, like so:
puts case
when (value_n_in_f > 0 && value_m_in_f != 1) then "I: f(x)=#{value_m_in_f}x+#{value_n_in_f}"
when (value_n_in_f == 0 && value_m_in_f != 1) then "I: f(x)=#{value_m_in_f}x"
end
Second, a case statement would be much more readable, like so:
def big_compare(value_n_in_f, value_m_in_f)
msg = case
when (value_n_in_f > 0 && value_m_in_f != 1) then "I: f(x)=#{value_m_in_f}x+#{value_n_in_f}"
when (value_n_in_f == 0 && value_m_in_f != 1) then "I: f(x)=#{value_m_in_f}x"
when (value_n_in_f < 0 && value_m_in_f != 1) then "I: f(x)=#{value_m_in_f}x#{value_n_in_f}"
when (value_n_in_f > 0 && value_m_in_f == 1) then "I: f(x)=x+#{value_n_in_f}"
when (value_n_in_f == 0 && value_m_in_f == 1) then "I: f(x)=x"
when (value_n_in_f < 0 && value_m_in_f == 1) then "I: f(x)=x#{value_n_in_f}"
end
end
puts big_compare(0, 0)

Fizz Buzz in Ruby for dummies

Spoiler alert: I am a true novice. Tasked with figuring out fizz buzz in
ruby for a class and while I have found more than a few versions of code
that solve the problem, my understanding is so rudimentary that I cannot
figure out how these examples truly work.
First question(refer to spoiler alert if you laugh out loud at this):
How do i print out numbers one through 100 in Ruby?
Second question: can 'if else" be used to solve this? My failed code is
below(attachment has screen shot):
puts('Lets play fizzbuzz')
print('enter a number: ')
number = gets()
puts(number)
if number == % 3
puts ('fizz')
elsif number == % 5
puts ('buzz')
elsif number == %15
puts ('fizzbuzz')
end
Thanks,
Thats ok being a novice, we all have to start somewhere right? Ruby is lovely as it get us to use blocks all the time, so to count to 100 you can use several methods on fixnum, look at the docs for more. Here is one example which might help you;
1.upto 100 do |number|
puts number
end
For your second question maybe take a quick look at the small implementation i whipped up for you, it hopefully might help you understand this problem:
1.upto 100 do |i|
string = ""
string += "Fizz" if i % 3 == 0
string += "Buzz" if i % 5 == 0
puts "#{i} = #{string}"
end
First question: this problem has several solutions. For example,
10.times { |i| puts i+1 }
For true novice: https://github.com/bbatsov/ruby-style-guide
another method that can be helpful :
puts (1..100).map {|i|
f = i % 3 == 0 ? 'Fizz' : nil
b = i % 5 == 0 ? 'Buzz' : nil
f || b ? "#{ f }#{ b }" : i
}
As a one liner
(1..100).map { |i| (i % 15).zero? ? 'FizzBuzz' : (i % 3).zero? ? 'Fizz' : (i % 5).zero? ? 'Buzz' : i }
In Regards to your failed code, your conditional statements should be like this:
if number % 3 == 0
puts "Fizz"
end
if number % 5 == 0
puts "Buzz"
end
You don't want the last elsif statement because it will never get executed
(if a number is not divisible by 3 or divisible by 5, then it is certainly not divisible by 15)
Adjust for this by changing the second elsif to simply and if and if the number is divisble by 5 and not by 3, then Fizz will not be outputted but Buzz Will be
I'm just showing you how to correct your code, but as others have pointed out, there are far more elegant solutions in Ruby.
Not the most beautiful way to write it but good for beginners and for readability.
def fizzbuzz(n)
(1..n).each do |i|
if i % 3 == 0 && i % 5 == 0
puts 'fizzbuzz'
elsif i % 3 == 0
puts 'fizz'
elsif i % 5 == 0
puts 'buzz'
else
puts i
end
end
end
fizzbuzz(100)
1.upto(100).each do |x| # Question #1 The 'upto' method here takes is
# what you would use to count in a range.
if (x % 3 == 0) && (x % 5 == 0)
puts " Fizzbuzz"
elsif x % 3 == 0
puts " Fizz"
elsif x % 5 == 0
puts " Buzz"
else
puts x
end
end
Question #2 Yes you can but I would look for a more elegant way to write this as a part of a definition like
def fizzbuzz(last_number)
1.upto(last_number).each do |x|
if (x % 3 == 0) && (x % 5 == 0)
puts " Fizzbuzz"
elsif x % 3 == 0
puts " Fizz"
elsif x % 5 == 0
puts " Buzz"
else
puts x
end
end
end
This is the answer that helped me to understand that no variables are being created with the .each method. Sorry about my indenting. Still learning how to use Stackoverflow text editing.
As for a more complex solution, that's one way you could build
a simple DSL for quickly modifying the FizzBuzz programme (adding new divisors with their own keywords)
class FizzBuzzer
# #return [Hash{String, Symbol => Integer}]
attr_reader :keywords
# #param keywords [Hash{String, Symbol => Integer}]
def initialize(keywords)
#keywords = keywords
end
# #param range [Range]
# #return [void]
def call(range)
range.each do |num|
msg = ''
#keywords.each do |name, divisor|
msg << name.to_s if (num % divisor).zero?
end
msg = num if msg.empty?
puts msg
end
puts
end
end
# create a fizz buzzer with custom keywords for divisors
CLASSIC_FIZZ_BUZZER = FizzBuzzer.new Fizz: 3, Buzz: 5
# print for a particular range
CLASSIC_FIZZ_BUZZER.call(1..25)
# you can easily define an extended fizz buzzer
EXTENDED_FIZZ_BUZZER = FizzBuzzer.new Fizz: 3, Buzz: 5, Bazz: 7, Fuzz: 11 # print 'Fuzz' when divisible by 11
EXTENDED_FIZZ_BUZZER.call(1..25)
Here's a quite elegant solution.
(1..100).each do |num|
msg = ''
msg << 'Fizz' if (num % 3).zero?
msg << 'Buzz' if (num % 5).zero?
msg = num if msg.empty?
puts(msg)
end
It can be even more compact
(1..100).each do |num|
(msg ||= '') << 'Fizz' if (num % 3).zero?
(msg ||= '') << 'Buzz' if (num % 5).zero?
puts msg || num
end
FizzBuzz
(1..100).each do |num|
if num % 3 == 0 && num % 5 == 0
puts "#{num}. FIZZBUZZ!"
elsif num % 3 == 0
puts "#{num}. FIZZ!"
elsif num % 5 == 0
puts "#{num}. BUZZ!"
else
puts "#{num}."
end
end
First question:
for i in 1..100
puts i
end
Here is my most "idiomatic ruby" solution:
class FizzBuzz
def perform
iterate_to(100) do |num,out|
out += "Fizz" if num.divisable_by?(3)
out += "Buzz" if num.divisable_by?(5)
out || num
end
end
def iterate_to(max)
(1..max).each do |num|
puts yield num,nil
end
end
end
class Fixnum
def divisable_by?(num)
self % num == 0
end
end
class NilClass
def +(other)
other
end
end
FizzBuzz.new.perform
And it works:
https://gist.github.com/galori/47db94ecb822de2ac17c

Resources