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

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.

Related

Ruby: Iterate the result from method using block

Now I have a ruby like this:
def fizzbuzz(numSize)
result = []
1.upto(numSize) do |num|
if num % 15 == 0
result << "FizzBuzz"
elsif num % 3 == 0
result << "Fizz"
elsif num % 5 == 0
result << "Buzz"
else
result << num.to_s
end
end
result
end
print fizzbuzz(10) {|item| "-#{i1tem}-"}
If I want to print the result like this:
["-1-", "-2-", "-Fizz-", "-4-", "-Buzz-", "-Fizz-", "-7-", "-8-", "-Fizz-", "-Buzz-"]
What can I modify my code in method fizzbuzz if I can not change the code:
print fizzbuzz(10) {|item| "-#{i1tem}-"}
Thanks
That block is being given to your method, but you're not making use of it. That's an easy fix:
def fizzbuzz(numSize, &block)
# ... (existing code) ...
result.map(&block)
end
Where that transforms the result value using map.
Note this requires fixing the typo in your print block which is i1tem not item.
It's also worth noting you should avoid this pattern:
x = [ ]
y.each do |v|
x << f(v)
end
x
That's just a long-winded version of this:
y.map do |v|
f(v)
end
Where when you're transforming on a 1:1 basis from the source just use map.
In your case that reduces the code to this more minimal form that has a lot less repetition:
def fizzbuzz(numSize, &block)
1.upto(numSize).map do |num|
if num % 15 == 0
"FizzBuzz"
elsif num % 3 == 0
"Fizz"
elsif num % 5 == 0
"Buzz"
else
num.to_s
end
end.map(&block)
end

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.

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

Is there a way to substitute operators depending on a condition?

I have an if/else condition, and the if and else sections are identical, save for the operator used. In one case <, and in the other >. Is there a way to conditionally set that operator, to DRY out the code?
if count_year < end_year
while count_year <= end_year
if count_year % 4 == 0
if count_year % 100 != 0
all_years << count_year unless (count_year % 400 == 0)
end
end
count_year += 1
end
puts all_years
elsif count_year > end_year
while count_year >= end_year
if count_year % 4 == 0
if count_year % 100 != 0
all_years << count_year unless (count_year % 400 == 0)
end
end
count_year -= 1
end
puts all_years.reverse
end
This is part of a program for printing out leap years between two given years. I feel like there must be a way to not have to repeat the loop twice. Something like: count_year < end_year ? operator = "<" : operator = ">" - Then using that variable to substitute the operator into a code block or something? Any ideas?
For one small improvement, you can extract really identical parts into a method. Then duplication stops being so massive.
# I'm too lazy to come up with a proper name for it.
def foo count_year, all_years
if count_year % 4 == 0
if count_year % 100 != 0
all_years << count_year unless (count_year % 400 == 0)
end
end
end
# later...
if count_year < end_year
while count_year <= end_year
foo count_year, all_years
count_year += 1
end
puts all_years
elsif count_year > end_year
while count_year >= end_year
foo count_year, all_years
count_year -= 1
end
puts all_years.reverse
end
But, the operator substitution...
Yes, there is a way to dynamically choose an operator for evaluation. You see, operators in ruby are just method calls, nothing more. These two lines are equivalent:
7 > 5
7.>(5)
And here's a snippet that chooses random operator for comparison. I leave it up to you to adapt it for your problem (if you want, that is. I advise you against this).
def is_7_greater_than_5
operator = [:<, :>].sample # pick random operator
7.send(operator, 5)
end
is_7_greater_than_5 # => false
is_7_greater_than_5 # => false
is_7_greater_than_5 # => true
is_7_greater_than_5 # => true
is_7_greater_than_5 # => true
def example count_year, end_year
all_years = []
dir, test = count_year < end_year ?
[ 1, proc { |c, e| c <= e }] : count_year > end_year ?
[-1, proc { |c, e| c > e }] :
[ 0, proc { |c, e| false }]
while test.call count_year, end_year
if count_year % 4 == 0
if count_year % 100 != 0
all_years << count_year unless count_year % 400 == 0
end
end
count_year += dir
puts dir > 0 ? all_years : all_years.reverse
end
end
Aww. Why did you do a code golf exercise and accept an answer so quickly? Boo! :( hehe. just kidding. The early bird gets the worm. I perhaps took the problem too literally as I think you're just looking to experiment with compare.
I would use the built in functions of ruby and decomposed this method into a class. :)
require 'date'
class LeapYearFinder
attr_reader :years, :years_reversed
def initialize(start_year, end_year)
#start_year = Date.parse("1/1/#{start_year.to_s}")
#end_year = Date.parse("1/1/#{end_year.to_s}")
#years ||= leap_years
end
def compare_range
#compare_range ||= Range.new(#start_year, #end_year)
end
def leap_years
years = []
compare_range.step {|x| years << x.year if x.leap? }
years.uniq!
end
def years_reversed
#years.reverse
end
end
lp = LeapYearFinder.new(1900, 2012)
puts "Years putzed"
lp.years.map {|x| puts x}
puts "Years reversed"
lp.years_reversed.map {|x| puts x}
Some corner case issues
handle a reverse date input
step properly through the range thus avoiding the uniq! and maybe yielding better performance

Resources