The title says it all. This is yet another FizzBuzz implementation where you can specify the words you want to use, though it autoselects the divisors as the first n primes other than 2, rather than having you enter them.
I'm looking for tips on variable/function naming and that kind of thing; I couldn't think of good ones when I wrote this. I'd also like any performance improvements that can be put in.
def n_primes(count)
primes = []
number = 2
until primes.length == count
primes << number if primes.inject(true) { |memo, cur| memo and number % cur != 0 }
number += 1
end
primes
end
puts 'Enter the words you would like to use'
word_array = gets.chomp.split
puts 'Enter the number to count up to'
up_to = gets.chomp.to_i
words = {}
primes = n_primes(word_array.length + 1)[1..-1]
primes.each_with_index { |prime, index| words[prime] = word_array[index] }
1.upto(up_to) do |number|
to_print = words.reject { |n, _| number % n != 0 }.values
to_print = [number] if to_print.length == 0
puts to_print.join ''
end
Note: I extracted n_primes
into a function because it means I don't have to use meaningless names like p
or num
to avoid naming conflicts. If there's a better solution, I'd like to know it.
Sample output:
Enter the words you would like to use
> Fizz Buzz Wolf Foo Bar
Enter the number to count up to
> 100
1
2
Fizz
4
Buzz
Fizz
Wolf
8
Fizz
Buzz
Foo
Fizz
Bar
Wolf
FizzBuzz
16
17
Fizz
19
Buzz
FizzWolf
Foo
23
Fizz
Buzz
Bar
Fizz
Wolf
29
FizzBuzz
31
32
FizzFoo
34
BuzzWolf
Fizz
37
38
FizzBar
Buzz
41
FizzWolf
43
Foo
FizzBuzz
46
47
Fizz
Wolf
Buzz
Fizz
Bar
53
Fizz
BuzzFoo
Wolf
Fizz
58
59
FizzBuzz
61
62
FizzWolf
64
BuzzBar
FizzFoo
67
68
Fizz
BuzzWolf
71
Fizz
73
74
FizzBuzz
76
WolfFoo
FizzBar
79
Buzz
Fizz
82
83
FizzWolf
Buzz
86
Fizz
Foo
89
FizzBuzz
WolfBar
92
Fizz
94
Buzz
Fizz
97
Wolf
FizzFoo
Buzz
(The user input is prefixed with >
, though it doesn't show up when you actually run the code)
1 Answer 1
#n_primes
Ruby has the
Prime
class as part of its stdlib, so you don't need to roll your own prime number generator.n_primes(word_array.length + 1)[1..-1]
A more Rubyesque version might use
drop(1)
instead of the[1..-1]
slice.words = {}
+primes.each_with_index
Instead of creating an empty Hash and then adding elements to it, you can use
Array#zip
to create an array of word/number pairs. You can turn that into a hash withHash[]
, if you'd like.words.reject
Purely from a semantic standpoint, I think
select
would be more natural to use. I think of it as "finding the words to print" rather than "discarding the words that shouldn't be printed" which sounds like a double negative.You could also consider using
#inject
or#each_with_object
to collect matches instead of#reject
+#values
to_print.length == 0
Use
Array#empty?
instead.to_print.join ''
You don't need the argument for
Array#join
.
I'd do this:
require "prime"
puts "Enter the words you would like to use (separated by spaces)"
words = gets.strip.split
puts "Enter the number to count up to"
count = gets.strip.to_i
pairs = Prime.first(words.count + 1).drop(1).zip(words)
1.upto(count) do |n|
line = pairs.each_with_object([]) do |(prime, word), memo|
memo << word if (n % prime).zero?
end
puts line.empty? ? n : line.join
end
Or, more in line with yours, the last part could be:
1.upto(count) do |n|
line = pairs.select { |prime, _| (n % prime).zero? }.map(&:last)
puts line.empty? ? n : line.join
end
-
\$\begingroup\$ I updated the doc link in your answer from 1.9.3 (IIRC) to 2.2.2, if you wanna accept the suggestion ;) \$\endgroup\$anon– anon2015年06月06日 20:14:45 +00:00Commented Jun 6, 2015 at 20:14
-
\$\begingroup\$ @QPaysTaxes Approved - I actually wanted to link to a newer one, but there was something weird going on with ruby-docs, and some of the 2.x doc pages kept saying "You've entered the forbidden area!"... with little in the way of explanation :) \$\endgroup\$Flambino– Flambino2015年06月06日 20:17:37 +00:00Commented Jun 6, 2015 at 20:17
-
\$\begingroup\$ @QPaysTaxes I just meant "a newer version than the 1.9 one I ended up posting" - not that the
Prime
class has changed very much in terms of API over the years, so it's not a huge deal either way. And oddly, the answer appears as accepted here, and I got some rep too (thanks!) \$\endgroup\$Flambino– Flambino2015年06月06日 20:20:23 +00:00Commented Jun 6, 2015 at 20:20 -
\$\begingroup\$ Oh, that makes sense. The API doc bit, at least. Still showing as not accepted here, and I've refreshed at least twice... Eh, I don't mind, so long as you get the rep \$\endgroup\$anon– anon2015年06月06日 20:21:57 +00:00Commented Jun 6, 2015 at 20:21
-
\$\begingroup\$ It's showing now... Odd. Still, unplugging the internet seems fun. BRB! \$\endgroup\$anon– anon2015年06月06日 20:25:53 +00:00Commented Jun 6, 2015 at 20:25