Home > Blockchain >  Ruby "Colorful Number" method for numbers with only three digits - absolute beginner -
Ruby "Colorful Number" method for numbers with only three digits - absolute beginner -

Time:10-08

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.

  •  Tags:  
  • ruby
  • Related