Initialize Array with Values (Ruby) - ruby

I was wondering if there was a way to initialize this array in one line:
mulof = []
(1..1000).each {|i| mulof << i if (i % 3 == 0 || i % 5 == 0)}

Yes there is using Enumerable#select :
mulof = (1..1000).select { |i| i % 3 == 0 || i % 5 == 0 }

Related

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"]

Using `map` to solve 'FizzBuzz'

I tired to use map to solve fizzbuzz.
def fizzbuzz(n)
array =(1..n).to_a
array.map{|x|
if x % 3 == 0 && x % 5 == 0
x = 'FizzBuzz'
elsif x % 3 == 0
x = 'Fizz'
elsif x % 5 == 0
x = 'Buzz'
end
}
array
end
Somehow, it doesn't work. Do you know what's wrong?
Method map does not change the original array. Use the bang version map! instead.
Using map! as suggested by #tmc and some other changes try:
def fizzbuzz(n)
array =(1..n).to_a
array.map!{|x|
if x % 3 == 0 && x % 5 == 0
x = 'FizzBuzz'
elsif x % 3 == 0
x = 'Fizz'
elsif x % 5 == 0
x = 'Buzz'
else
x = x
end
}
p array
end
fizzbuzz(10) #=> [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz"]
As you can see I've added a call to the method fizzbuzz with an argument of 10 which you can change. And I've used p to inspect the array as well as a final else statement.

Ruby: FizzBuzz not working as expected

I'm having trouble getting an IF statement to produce the results I think they should. I'm not sure why I cannot get the && ("and") conditional to work.
def fizzbuzz(n)
pool = []
(1..n).each do |x|
if x % 3 == 0
pool.push('Fizz')
elsif x % 5 == 0
pool.push('Buzz')
elsif x % 3 == 0 && x % 5 == 0
pool.push('FizzBuzz')
else
pool.push(x)
end
end
puts pool
end
fizzbuzz(10)
and they results
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
I'm not sure what I'm doing wrong here.
Try this instead:
def fizzbuzz(n)
pool = []
(1..n).each do |x|
if x % 3 == 0 && x % 5 == 0
pool.push('FizzBuzz')
elsif x % 5 == 0
pool.push('Buzz')
elsif x % 3 == 0
pool.push('Fizz')
else
pool.push(x)
end
end
puts pool
end
When you use if/elsif/elsif/else, it will execute only one of this conditions at time. If x % 3 == 0, then that's it, ruby will no longer enter any of those conditions, that's why fizzbuzz will never be printed.
The if/else if/else branching only executes one of the code blocks. If a condition is true, then the following block is executed and the program will skip to the end of the if/else statements.
Here is another working version, which is a bit cleaner, but as Tiago Farias said, you wont get the 'fizzbuzz' message printed in a range from [1..10], because you don't have a value which will have the rest 0 for both % 3 and % 5, the closest will be 15.
def fizzbuzz(n)
#pool = []
(1..n).each do |x|
send_no x
end
puts #pool
end
def send_no x
return #pool << 'fizzbuzz' if x % 3 == 0 && x % 5 == 0
return #pool << 'fizz' if x % 3 == 0
return #pool << 'buzz' if x % 5 == 0
#pool << x
end
fizzbuzz(10)

How can I DRY this series of conditional statements?

I often find myself checking multiple conditions. How can I cut down on the number of lines used to achieve the same effect?
def super_fizzbuzz(array)
final = []
for num in array
if num % 15 == 0
final << 'FizzBuzz'
elsif num % 5 == 0
final << 'Buzz'
elsif num % 3 == 0
final << 'Fizz'
else
final << num
end
end
final
end
def super_fizzbuzz(array)
array.map do |num|
a = []
a << 'Fizz' if num % 3 == 0
a << 'Buzz' if num % 5 == 0
a.empty? ? num : a.join()
end
end
def super_fizzbuzz(array)
final = []
array.each do |num|
num % 15 == 0 ? final << 'FizzBuzz' : num % 5 == 0 ? final << 'Buzz' : num % 3 == 0 ? final << 'Fizz' : final << num
end
final
end
But your way is more readable.
def super_fizzbuzz(array)
array.map do |num|
case 0
when num % 15 then "FizzBuzz"
when num % 5 then "Buzz"
when num % 3 then "Fizz"
else num
end
end
end
This is slightly more complex, but reduces number of explicit coded conditionals to 2:
FIZZBUZZ = { 3 => 'Fizz', 5 => 'Buzz' }
def super_fizzbuzz(array)
array.map do |num|
fbs = FIZZBUZZ.select do |divisor,cat|
num % divisor == 0
end.values
fbs.empty? ? num : fbs.join
end
end
There is always the danger when coding for DRY that you take things too far. In this case, with only two overlapping categories, I think the above is a little unwieldy. However, add another category or two:
FIZZBUZZ = { 3 => 'Fizz', 5 => 'Buzz', 7 => 'Boom', 11 => 'Whizz' }
and it starts to look smarter.
Quote:
I think Fizz-Buzz is "hard" for some programmers because (#1) it doesn't fit into any of the patterns that were given to them in school assignments, and (#2) it isn't possible to directly and simply represent the necessary tests, without duplication, in just about any commonly-used modern programming language.
Source: c2.com Wiki
Another way:
def super_fizzbuzz(arr)
arr.map do |e|
s = ''
s << 'Fizz' if (e%3).zero?
s << 'Buzz' if (e%5).zero?
s = e if s.empty?
s
end
end
super_fizzbuzz [9, 25, 225, 31]
#=> ["Fizz", "Buzz", "FizzBuzz", 31]

ruby inject with conditional in block?

doing the first Project Euler question: summing the multiples of 3 and 5 between 1 and 1000, I came up with this (pretty simple)
sum = 0
1.upto(999) { |i| sum += i if 0 == i%3 || 0 == i%5 }
sum
but I thought this would work but it doesn't, can someone show me what I'm doing wrong, or why it doesn't work?
1.upto(999).inject(0) { |sum, i| sum + i if 0 == i%3 || 0 == i%5 }
thanks!
inject passes the result of the block through to the next iteration as the first argument. Your block will return nil when your if statement is false, which then gets passed back in as sum.
To get the correct answer, the block should return the current sum when it's false:
1.upto(999).inject(0) { |sum, i| (0 == i%3 || 0 == i%5) ? sum + i : sum }
Complementary answer: if you're about to tackle Euler problems you should start to build your own extensions of reusable code. In this case, the first extension would be Enumerable#sum:
module Enumerable
def sum
inject(0, :+)
end
end
And now you can write a solution that separates the condition of the summatory (you can read it out loud and it makes sense, that's typical of functional/declarative style):
1.upto(999).select { |x| x % 3 == 0 || x % 5 == 0 }.sum
You could even push it one step further and create Fixnum#divisible_by? so you can write:
1.upto(999).select { |x| x.divisible_by?(3) || x.divisible_by?(5) }.sum
More: here it's not a problem, but later on strict implementations (those using arrays) will require too much memory. Try then with laziness:
require 'lazy'
1.upto(999).lazy.select { |x| x % 3 == 0 || x % 5 == 0 }.sum
1.upto(999).inject(0) { |sum, i| sum += i if 0 == i%3 || 0 == i%5; sum }
Would also work (note the +=).
Or, use & proc which addresses self.
(1..999).select{|x| x%3==0||x%5==0}.inject &:+
(1..999).to_a.keep_if{|d| d%3 == 0 || d%5 == 0}.reduce(:+) for completeness.

Resources