Why doesn't the ternary syntax work in this situation? - ruby

This is valid:
def prime? n
(2...n).each {|num| return false if n % num == 0 }
true
end
This is NOT valid
def prime? n
(2...n).each {|num| n % num == 0 ? return false : true }
end
Aren't these both saying the same thing? Why does the second example cause a syntax error?
Now why does this next example work in the ternary syntax?
def primes max
primes_arr = []
(2...max).map { |num| prime?(num) ? primes_arr << num : next }
primes_arr
end

That code cause a syntax error because the ruby interpreter don't know, where the arguments for return keyword has end up, the correct example is:
def prime? n
(2...n).each {|num| n % num == 0 ? ( return false ) : true }
end
Here is the next isn't really required just use boolean logic:
def primes max
primes_arr = []
(2...max).map { |num| prime?(num) && primes_arr << num }
primes_arr
end
If we do some optimization, we can do:
def prime? n
(2...n).all? {|num| n % num != 0 }
end
def primes max
(2...max).select {|num| prime?(num) }
end
Next level of optimization shell be this:
def primes max
(2...max).select {|num| (2...num).all? {|num1| num % num1 != 0 } }
end
primes 7
# => [2, 3, 5]

Adding parenthesis to explicitly state the way Ruby is interpreting what you have:
(2...n).each { |num| (n % num == 0 ? return false) : true }
We can verify this in that we get the same error message with and without the parenthesis:
SyntaxError: (eval):2: syntax error, unexpected keyword_false, expecting ':'
You can solve this by giving explicit parenthesis to force Ruby to interpret it how you want:
(2...n).each { |num| n % num == 0 ? (return false) : true }
Or you can only return false when the case is met (as you have in your question). Or, better yet, use any? instead:
(2...n).any? { |num| n % num != 0 }

Here's a proper usage of ternary operator (no operator at all :) )
def prime? n
!(2...n).any? {|num| n % num == 0 }
# or
# (2...n).all? {|num| n % num != 0 }
end
(1..10).each do |x|
puts "prime?(#{x}) \# => #{prime?(x)}"
end
# >> prime?(1) # => true
# >> prime?(2) # => true
# >> prime?(3) # => true
# >> prime?(4) # => false
# >> prime?(5) # => true
# >> prime?(6) # => false
# >> prime?(7) # => true
# >> prime?(8) # => false
# >> prime?(9) # => false
# >> prime?(10) # => false

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

How to optimize code - it works, but I know I'm missing much learning

The exercise I'm working on asks "Write a method, coprime?(num_1, num_2), that accepts two numbers as args. The method should return true if the only common divisor between the two numbers is 1."
I've written a method to complete the task, first by finding all the factors then sorting them and looking for duplicates. But I'm looking for suggestions on areas I should consider to optimize it.
The code works, but it is just not clean.
def factors(num)
return (1..num).select { |n| num % n == 0}
end
def coprime?(num_1, num_2)
num_1_factors = factors(num_1)
num_2_factors = factors(num_2)
all_factors = num_1_factors + num_2_factors
new = all_factors.sort
dups = 0
new.each_index do |i|
dups += 1 if new[i] == new[i+1]
end
if dups > 1
false
else
true
end
end
p coprime?(25, 12) # => true
p coprime?(7, 11) # => true
p coprime?(30, 9) # => false
p coprime?(6, 24) # => false
You could use Euclid's algorithm to find the GCD, then check whether it's 1.
def gcd a, b
while a % b != 0
a, b = b, a % b
end
return b
end
def coprime? a, b
gcd(a, b) == 1
end
p coprime?(25, 12) # => true
p coprime?(7, 11) # => true
p coprime?(30, 9) # => false
p coprime?(6, 24) # => false```
You can just use Integer#gcd:
def coprime?(num_1, num_2)
num_1.gcd(num_2) == 1
end
You don't need to compare all the factors, just the prime ones. Ruby does come with a Prime class
require 'prime'
def prime_numbers(num_1, num_2)
Prime.each([num_1, num_2].max / 2).map(&:itself)
end
def factors(num, prime_numbers)
prime_numbers.select {|n| num % n == 0}
end
def coprime?(num_1, num_2)
prime_numbers = prime_numbers(num_1, num_2)
# & returns the intersection of 2 arrays (https://stackoverflow.com/a/5678143)
(factors(num_1, prime_numbers) & factors(num_2, prime_numbers)).length == 0
end

Ruby Program to solve Circular Primes below number x

I'm working on project Euler #35. I am getting the wrong number returned and I can't find where I have done wrong!
def is_prime?(num)
(2..Math.sqrt(num)).each { |i| return false if num % i == 0}
true
end
def is_circular?(num)
len = num.to_s.length
return true if len == 1
(len - 1).times do
new_n = cycle(num)
break unless is_prime?(new_n)
end
end
def cycle(num)
ary = num.to_s.split("")
return ary.rotate!.join.to_i
end
def how_many
circulars = []
(2..1000000).each do |num|
if is_prime?(num) && is_circular?(num)
circulars << num
end
end
p circulars.count
end
how_many #=> 14426
The returned number is '14426'. I am only returning the circular primes, supposedly the correct answer is '55'
I have edited your code with few fixes in Ruby way. Your mistake was including corect set of [a, b, c] three times to count, instead of counting them as a one circular prime number. Your answer was correct, while 55 is the number of unique sets.
require 'prime'
class Euler35
def is_circular?(num)
circulars_for(num).all?{ |el| ::Prime.instance.prime?(el) }
end
def circulars_for(a)
a.to_s.split("").length.times.map{|el| a.to_s.split("").rotate(el).join.to_i }
end
def how_many
circulars = []
::Prime.each(1_000_000) do |num|
continue if circulars.include?(num)
if is_circular?(num)
circulars << circulars_for(num)
end
end
circulars.count
end
end
puts Euler35.new.how_many # => 55

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]

Finding a prime number using a **custom** Ruby method

I would like to pass an array of numbers to my is_prime? method and return if the numbers are valid or not. I do not want to use:
require 'prime'
a = [1,2,3,4,5]
Hash[a.zip(a.map(&Prime.method(:prime?)))]
This is learning experience. My current code is only outputing the first number in the array. Can someone help me understand what I am doing wrong? Thanks!
def is_prime?(*nums)
i = 2
nums.each do |num|
while i < num
is_divisible = ((num % i) == 0)
if is_divisible == false
x = "#{num}: is NOT a prime number." #false
else
x = "#{num}: is a prime number." #true
end
i +=1
end
return x
end
end
puts is_prime?(27,13,42)
You are returning in the loop.
A few bugs in your method:
def is_prime?(*nums)
nums.each do |num|
return false if num == 1
next if num == 2 # 2 is the only even prime
i = 2 # needs to be reset for each num
while i < num
return false if num % i == 0 # num is not prime
i += 1
end
end
true # We'll reach here only if all the numbers are prime
end
This will return your results in the same format as your usage of the prime library with the same logic as your custom function:
def is_prime?(*nums)
nums.each_with_object({}) do |num, hsh|
hsh[num] = num > 1 && 2.upto(num - 1).none? { |i| num % i == 0 }
end
end
puts is_prime?(27,13,42)
# => {27=>false, 13=>true, 42=>false}
Since you mention this is just for learning, I'm assuming you know that a sieve is a better way to go for this than brute force iteration.
If you want an explanation of how the above code works or further help understanding why your current code doesn't, let me know in the comments.

Resources