How to make this Python function for finding colourful numbers operate on any number?

336 views Asked by At

A colourful number is one that includes no duplicates in the list of it digits + the products of the subsets of its digits. For example, the products of 263 are [2, 6, 3, 2x6, 6x3, 2x6x3]. These are all different numbers, so 263 is colourful.

I made some code to allow this for integers up to length 3. It does work. It makes a list of the digits and subsets, then converts that list into a set to remove duplicates, then compares list to set. If there are no duplicates the lengths will be the same.

However it should scale for any length of int. It is also very far from concise. How should I make it scale and make it readable?

Here is my function. It works for values up to length 3.

def is_colorful(num):

    str_num = str(num)
    combos = []

    if len(str_num) == 1:

        x = int(str_num[0])

        combos.append(x)

    if len(str_num) == 2:

        x = int(str_num[0])
        y = int(str_num[1])

        combos.append(x)
        combos.append(y)
        combos.append(x*y)

    if len(str_num) == 3:

        x = int(str_num[0])
        y = int(str_num[1])
        z = int(str_num[2])
        
        combos.append(x)
        combos.append(y)
        combos.append(z)
        combos.append(x*y)
        combos.append(y*z)
        combos.append(x*y*z)

    set_combos = set(combos)
    print(set_combos)
    
    return True if len(set_combos) == len(combos) else False
1

There are 1 answers

0
constantstranger On

Here's a way to scale it:

def is_colorful(num):
    # disqualify as colorful if:
    #    - there are multiple digits and one of them is 0 or 1
    #    - any digit is a duplicate
    n, prods = num, set()
    while n:
        digit = n % 10
        if prods and digit in (0,1) or digit in prods:
            return False
        n, prods = n // 10, prods | {digit}
    
    # disqualify as colorful if:
    #    - the product of the digits in any subset is a duplicate
    n, prods = num, set()
    while n:
        digit, curProds = n % 10, set()
        for prd in (p * digit for p in (f for group in (prods, [1]) for f in group)):
            if prd in prods:
                return False
            curProds.add(prd)
        n, prods = n // 10, prods | curProds
    return True

top = 1
while top <= 10_000_000:
    colorful = []
    for i in range(top):
        if is_colorful(i):
            colorful.append(i)
    print(f'for 0 to {top}, ', 
        f'the count of colorful numbers is {len(colorful)}), ',
        f'percent = {100 * len(colorful) / top}%')
    top *= 10

Output:

for 0 to 1, the count of colorful numbers is 1, percent = 100.0%
for 0 to 10, the count of colorful numbers is 10, percent = 100.0%
for 0 to 100, the count of colorful numbers is 74, percent = 74.0%
for 0 to 1000, the count of colorful numbers is 454, percent = 45.4%
for 0 to 10000, the count of colorful numbers is 2194, percent = 21.94%
for 0 to 100000, the count of colorful numbers is 7690, percent = 7.69%
for 0 to 1000000, the count of colorful numbers is 17530, percent = 1.753%
for 0 to 10000000, the count of colorful numbers is 23290, percent = 0.2329%