I'm an absolute coding beginner and have just started to learn ruby. I had a challenge where I was supposed to check if a number was "colorful".
When in a given number, product of every digit of a sub-sequence are different. That number is called Colorful Number.
For example, "263 is a colorful number because [2, 6, 3, 2*6, 6*3, 2*6*3] are all different; whereas 236 is not colorful, because [2, 3, 6, 2*3, 3*6, 2*3*6] have 6 twice.
So take all consecutive subsets of digits, take their product and ensure all the products are different."
In the challenge given we were to only accept numbers up to three digits.
So since I am a beginner I tried to write every product seperately. I know this is not "good" code, but still I want to understand why it is not working. I think it should... but it doesn't :)
I would be so glad if someone could tell my why this is not working. I am not looking for a nicer solution, I really just want to know why mine doesn't work.
THANK YOU SO MUCH!
def colorful?(number)
if number.class != Integer
return false
elsif number.to_s.length > 3
return false
elsif number == 0 || 1
return true
end
digits_arr = number.digits.reverse
product_1 = digits_arr[0]*digits_arr[1]
product_2 = digits_arr[1]*digits_arr[2]
product_3 = digits_arr[0]*digits_arr[1]*digits_arr[2]
final_array = digits_arr product_1 product_2 product_3
if final_array.uniq.length == final_array.length
return true
else
return false
end
end
CodePudding user response:
So, your biggest issue is here:
elsif number == 0 || 1
This means "when number is equal to 0 OR when 1 is truthy value". In Ruby, 1
is always a truthy value, so this condition is always satisfied, leading to the execution of return true
, terminating your method and returning true
for any value.
Once you replace it with either
elsif number == 0 || number == 1
or
elsif [0,1].include? number
you will still have some more issues to fix - next one will be No implicit conversion of Integer into an Array
when you try to add number to an Array. I hope you'll figure this one out by yourself. :)
While we're here, few minor notes.
In Ruby, we prefer duck-typing over strong types (mostly becuase we don't have strong typing) so any form of argument type checks like if number.class != Integer
is thrown upon (not to mention it won't work very well as you will reject a large number of other Numeric
classes - if you have to chack for classes use is_a?
or kind_of?
). Note that if your method is ever executed with something that is not a number, you do want to throw an exception rather than let the calculation continue - it is much easier to prevent your system from getting into a bad state than debugging the bad state and guessing how you got there.
Might be personal opinion here, but elsif
sucks - almost always there is a better way. In this scenario, since you're returning in each case, you could just do:
return false unless number.is_a? Integer # really unnecessary
return false if number.to_s.length > 3
return true if number == 0 || number == 1
CodePudding user response:
require 'set'
def colorful?(n)
digits = n.digits.reverse
products = Set.new
(1..digits.size-1).each do |n|
digits.each_cons(n) { |a| return false unless products.add?(a.reduce(:*)) }
end
true
end
colorful? 263
#=> true
colorful? 236
#=> false
colorful? 3245
#=> true
See Set#add?
I can best show how the method works by adding some puts
statements and executing the method for two of the example integers above.
def colorful?(n)
digits = n.digits.reverse
puts "digits = #{digits}"
products = Set.new
(1..digits.size-1).each do |n|
puts "n = #{n}"
puts "digits.each_cons(#{n}).to_a #=> #{digits.each_cons(n).to_a}"
digits.each_cons(n) do |a|
m = a.reduce(:*)
puts " a = #{a}, m = #{m}"
puts " products = #{products}"
puts " products.include?(#{m}) = #{products.include?(m)}"
return false unless products.add?(m)
end
end
puts "true is returned"
true
end
colorful? 263
#=> true
The following is displayed.
digits = [2, 6, 3]
n = 1
digits.each_cons(1).to_a #=> [[2], [6], [3]]
a = [2], m = 2
products = #<Set: {}>
products.include?(2) = false
a = [6], m = 6
products = #<Set: {2}>
products.include?(6) = false
a = [3], m = 3
products = #<Set: {2, 6}>
products.include?(3) = false
n = 2
digits.each_cons(2).to_a #=> [[2, 6], [6, 3]]
a = [2, 6], m = 12
products = #<Set: {2, 6, 3}>
products.include?(12) = false
a = [6, 3], m = 18
products = #<Set: {2, 6, 3, 12}>
products.include?(18) = false
true is returned
colorful? 236
#=> false
The following is displayed.
digits = [2, 3, 6]
n = 1
digits.each_cons(1).to_a #=> [[2], [3], [6]]
a = [2], m = 2
products = #<Set: {}>
products.include?(2) = false
a = [3], m = 3
products = #<Set: {2}>
products.include?(3) = false
a = [6], m = 6
products = #<Set: {2, 3}>
products.include?(6) = false
n = 2
digits.each_cons(2).to_a #=> [[2, 3], [3, 6]]
a = [2, 3], m = 6
products = #<Set: {2, 3, 6}>
products.include?(6) = true
Because products
was found to contain m
(3
), false
was returned.