Having trouble with conditionals - ruby

I'm trying to define a method that returns "fizz" when the integer is divisible by 3, "buzz" when is divisible by 5 and "fuzzbuzz" when the number is divisible by both. I know 15 is divisible by both, however I don't know what I'm inputting wrong in my code. Thank you.
def fizzbuzz(int)
if int % 3 == 0
return "Fizz"
elsif int % 5 == 0
return "Buzz"
elsif int % 15 == 15
return "FizzBuzz"
else
end
end

So for conditionals, ruby evaluate the if, then the elsif, and finally the else in order. If anything condition evaluates to true, then the rest of the conditions are ignored.
def fizzbuzz(int)
if int % 3 == 0
return "Fizz"
elsif int % 5 == 0
return "Buzz"
elsif int % 15 == 15
return "FizzBuzz"
else
end
end
So let's look at a few examples based on your current code.
Say int = 3
We go to if int % 3 == 0, which is true, so the code return "Fizz" and nothing below that is evaluated.
Say int = 5,
int % 3 == 0 is false, we move onto the first elsif.
int % 5 == 0 is true, we return "Buzz"
Now let's look at 15,
int % 3 == 0 is true, so the code will return "Fizz" and ignores everything else, even if there are more conditions that will evaluate to be true after the if statement.
The order here is very important. You will want to check if int % 15 == 0 first, then move onto % 3 and % 5.

Related

Method involving a conditional loop is unexpectedly returning nil for some values

I'm trying to solve a Ruby challenge. The aim is to write a method that returns true if a random integer (including negative integers and 0) inputted as an argument is prime, and false if it is not. My method returns the right results, when it returns results.
I've tested the method for the numbers 1-20. It returned:
true for all 7 primes under 20 except 3, which was nil
false for 1, 9 and 15
nil for everything else
I also tested 43 (true) and 100 and 80 (nil). I also noticed that if I commented out the lines with return, the method returned nil for all arguments between 1 and 20.
Here's the method:
def isPrime(num)
num_absolute = num.abs
increasing_divisor = 2
almost_num_absolute = num_absolute - 1
if num_absolute <=1
return false
elsif num_absolute == 2
return true
else
until num_absolute % increasing_divisor == 0 || almost_num_absolute == increasing_divisor
increasing_divisor += 1
if num_absolute % increasing_divisor == 0
return false
elsif almost_num_absolute == increasing_divisor
return true
end
end
end
end
Your issue is that the body of this until loop is not always run:
until num_absolute % increasing_divisor == 0 || almost_num_absolute == increasing_divisor
Let's say that I pass a input of 3. This is a prime, so this loop will run until almost_num_absolute == increasing_divisor. At which point the until block will finish, and since your fuction doesn't specify any return value after the until block, it will just return nil (which is the 'default' return value for functions).
Now let's say you pass an input of 6. The value of increasing_divisor is 2 (the starting value). 6 is divisible by 2. So, because num_absolute % increasing_divisor == 0 is true, the body of the until block will never run. Again, no return value is specified after the until block, so the default return value (nil) is used.
A quick fix would be to add this line at the way end of the function (right before the final end):
almost_num_absolute == increasing_divisor
Since both primes and non-primes can reach this point in the code, you want to do a final check here. If almost_num_absolute == increasing_divisor is true, then you know there were no divisors found, and therefore the result is a prime

Ruby FizzBuzz using arrays, my logic seems right but it is getting an error

FizzBuzz, a classic problem, returns all the numbers up to N with a slight twist. If a number is divisible by 3, it is replaced with "fizz". If it's divisible by 5, it's replaced with "buzz". If it's divisible by both, it's replaced with "fizzbuzz"
I keep getting this Error message:
comparison of Fixnum with nil failed
Can someone explain this error message to me please? Also why is the code not working?
def fizz_buzz(n)
arr = (1..n).to_a
i = 0
while arr[i] < arr[n]
if i % 3 == 0 && i % 5 == 0
arr[i] = 'fizzbuzz'
elsif i % 3 == 0
arr[i] = 'fizz'
elsif i % 5 == 0
arr[i] = 'buzz'
else
arr[i] = i
i += 1
end
end
return arr
end
fizz_buzz(12)
Your conditions are just a bit off, give this a try:
def fizz_buzz(n)
arr = (1..n).to_a
i = 0
while i < n
if arr[i] % 3 == 0 && arr[i] % 5 == 0
arr[i] = 'fizzbuzz'
elsif arr[i] % 3 == 0
arr[i] = 'fizz'
elsif arr[i] % 5 == 0
arr[i] = 'buzz'
end
i+=1
end
return arr
end
Trying to access arr[n] puts you outside the bounds of the array which returns nil in Ruby.
You can update the code the ruby way, by using blocks and guards, I don't remember last time I used a while loop in ruby :)
Also, Array.new accepts a block as an argument which you can exploit to build your Array in a single step:
def fizz_buzz(n)
Array.new(n) do |index|
x = index + 1
case
when x % 3 == 0 && x % 5 == 0 then "fizzbuzz"
when x % 3 == 0 then "fizz"
when x % 5 == 0 then "buzz"
else x
end
end
end
Notice I used 1 as a base index and not 0, you can just remove x = index + 1 and replace x with index to have it working in a zero index base
A solution with a block instead of the while loop, and guards
def fizz_buzz(n)
arr = (1..n).to_a
0.upto(n - 1) do |i|
arr[i] = "fizzbuzz" and next if i % 3 == 0 && i % 5 == 0
arr[i] = "fizz" and next if i % 3 == 0
arr[i] = "buzz" if i % 5 == 0
end
arr
end
#brad-melanson beat me to the straight-forward answer to your question, so I'll share an answer which uses some common Ruby idioms (passing a range to the Array constructor and map), which simplify things, prevent you from having to do any iteration bookkeeping and prevent the possibility of off-by-one errors, out-of-bounds errors, etc.
def fizz_buzz(n)
Array(1..12).map do |n|
if n % 3 == 0 && n % 5 == 0
'fizzbuzz'
elsif n % 3 == 0
'fizz'
elsif n % 5 == 0
'buzz'
else
n
end
end
end
result = fizz_buzz 12
# result => [1, 2, "fizz", 4, "buzz", "fizz", 7, 8, "fizz", "buzz", 11, "fizz"]

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.

Lambdas and only 1 argument in case statements in Ruby

As I get it, you can use a proc/lambda inside, switch, for example:
is_even = ->(x) { x % 2 == 0 }
case number
when 0 then puts 'zero'
when is_even then puts 'even'
else puts 'odd'
end
As I understand it, and from the examples I see, is it that lambdas can be used in case statements ONLY IF they accept only 1 parameter, since you can't do a case statement with more than 1 argument (case a, b isn't possible, except if maybe these elements are enclosed into an array). So basically if you try to use a lambda with more than 1 parameter in a case statement the code is going to break. Correct me if I'm wrong.
It's because:
is_even = ->(x) { x % 2 == 0 }
is_even.lambda? #true
is "lambda" ( is_even = lambda(x) { x % 2 == 0 } is equivalent of above code)
There exist procs:
is_even = proc{|x| x % 2 == 0 } # Proc.new{|x| x % 2 == 0 }
is_even.lambda? #false
lambdas checks for number of arguments. procs on other hand doesn't check number of arguments.
ppp1 = Proc.new{|x| x % 2 == 0 } #=> #<Proc:0x507f300#(pry):152>
ppp1.call(2,3,4,5) #true
ppp2 = ->(x){ x % 2 == 0 } # => #<Proc:0x2c5ac40#(pry):158 (lambda)>
ppp2.(2,4) # ArgumentError: wrong number of arguments (2 for 1)
You can read more here.

FizzBuzz using ternary conditional operator

I've been reading up on conditional-style expressions in ruby. However I came across one I couldn't quite understand to define the classic FizzBuzz problem. I understand the FizzBuzz problem and even wrote my own before finding the following quick solution utilising the ternary operator. If someone can explain to me how this chain works to satisfy the FizzBuzz problem it would be very much appreciated :)
for i in 0...100
puts i%3==0 ? i%5==0 ? "FizzBuzz" : "Buzz" : i%5==0 ? "Fizz" : i
end
Some parentheses might help:
puts (i%3 == 0) ? ((i%5 == 0) ? "FizzBuzz" : "Buzz") : ((i%5 == 0) ? "Fizz" : i)
So, if i is divisible by 3, then it checks whether i is also divisible by 5. If so, it prints "FizzBuzz" otherwise just "Buzz". If i is not divisible by three, then it checks divisibility by 5 again and prints "Fizz" if so, otherwise just i.
Here is a description of the FizzBuzz problem as stated in this Jeff Atwood article.
Write a program that prints the
numbers from 1 to 100. But for
multiples of three print "Fizz"
instead of the number and for the
multiples of five print "Buzz". For
numbers which are multiples of both
three and five print "FizzBuzz".
A ternary operator is shorthand writing for an if-else statement. The general format is:
cond ? evaluate_if_cond_is_true : evaluate_if_cond_is_false
So if I write:
int isEven = (i % 2 == 0) ? 1 : 0;
Is equivalent to the following code:
if (i % 2 == 0) {
isEven = 1;
} else {
isEven = 0;
}
Where cond is i % 2 == 0, evaluate_if_cond_is_true is 1 and evaluate_if_cond_is_false is 0.
The nice thing about ternary operators is that they can be combined. This means that the statement to execute when either condition evaluates to true or false can be another ternary operator.
Let put the entire condition in a more readable fashion:
i%3==0 ?
i%5==0 ?
"FizzBuzz"
: "Buzz"
: i%5==0 ?
"Fizz"
: i
And mapping this to if-else statements is easy with the rules explained above:
if (i%3==0) {
if (i%5==0) {
"FizzBuzz"
} else {
"Buzz"
}
} else {
if (i%5==0) {
"Fizz"
} else {
i
}
}
This is not valid code but because the result of the ternary operator is inlined in the result expression it is used as input for the puts command.
For fun, here's another way:
puts (1..100).map {|i| (fb = [["Fizz"][i%3],["Buzz"][i%5]].compact.join).empty? ? i : fb}
And another:
(1..100).zip([nil,nil,"Fizz"]*34,[nil,nil,nil,nil,"Buzz"]*20).map {|a,b,c| b || c ? [b,c].join : a}
The ternary is a basic if-then structure.
The above is equivalent to...
if i%3 ==0
if i%5 == 0
"FizzBuzz"
else
"Buzz"
else
if i%5 == 0
"Fizz"
else
i
Or, using some parens...
puts i%3==0 ? ( i%5==0 ? "FizzBuzz" : "Buzz" ) : ( i%5==0 ? "Fizz" : i )
the flow is:
if (i%3 == 0) { // multiple of 3
if (i%5 == 0) { // multiple of 3 and 5
puts "FizzBuzz"
} else { // not multiple of 5, only of 3
puts "Buzz"
}
} else ( // not multiple of 3
if (i%5 == 0) { // multiple of 5, not of 3
puts "Fizz"
} else { // multiple of neither 5 nor 3
puts i
}
}
Just for fun. If you wanted to do it in C#. Here's a simple way. It basically starts with your for loop that will print numbers from 1 to 100. It then asks if your index "i" is divisible by 3 and 5 if true then print to the console "FizzBuzz". Else if your index "i" is divisible by 3 if true then print to the console "Fizz". Else if your index "i" is divisible by 5 if true then print to the console "Buzz". Else just print out "i" which is your integer. I added tabbing for better readability.
for(int i = 1; i <= 100; i++) {
string result = (i % 3 == 0 && i % 5 == 0) ?
"FizzBuzz" :
(i % 3 == 0) ?
"Fizz" :
(i % 5 == 0) ?
"Buzz" :
i.ToString();
Console.WriteLine(result);
}

Resources