2

I am attempting to cycle through the alphabet so it will print '0, 1, 2, 3' and 'a, b, c' and '!' and so on. After all the characters have been cycled through, I want to then have it go 'aa' 'ab' and 'a0' and so on. This is the working code I have so far:

alph = {
    0: '0',
    1: '1',
    2: '2',
    3: '3',
    4: '4',
    5: '5',
    6: '6',
    7: '7',
    8: '8',
    9: '9',
    10: 'a',
    11: 'b',
    12: 'c',
    13: 'd',
    14: 'e',
    15: 'f',
    16: 'g',
    17: 'h',
    18: 'i',
    19: 'j',
    20: 'l',
    21: 'm',
    22: 'n',
    23: 'o',
    24: 'p',
    25: 'q',
    26: 'r',
    27: 's',
    28: 't',
    29: 'u',
    30: 'v',
    31: 'w',
    32: 'x',
    33: 'y',
    34: 'z',
    35: '!'
}


def one(sweet):
    print sweet

def yeah():
    i = 0
    while 1==1:
        if divmod(i,36)[0] == 0:
            a = alph[divmod(i, 36)[1]]
            sweet = a
            one(sweet)
            i += 1

        elif divmod(i,36)[0] < 36:
            b = alph[divmod(i, 36)[1]]
            a = alph[divmod(i, 36)[0]]
            sweet = a + b
            one(sweet)
            i += 1

    return false

yeah()

This part works great! it will print out 'a' through '!!'. The part I'm struggling to wrap my head around is the third part:

        elif divmod(i,36)[0] < 36**2:
            c = alph[divmod(i, 36)[1]]
            b = alph[divmod((i//36), 36)[0]]
            a = alph[divmod(i, 36)[0]]
            sweet = a + b + c
            one(sweet)
            i += 1

This should print 'aaa' 'aab' and so on. I am not sure how to go about this. After doing this. I also realized that I would have to create an infinite amount of 'elif' statements, one for 'aaaa' another for 'aaaaa' and etc. What would be the best way to go about creating a function that could potentially go to infinity?

chriscrutt
  • 500
  • 3
  • 5
  • 17
  • You want just `'a'+whatever` or want combinations? – U13-Forward Sep 26 '18 at 01:39
  • 1
    `divmod(i,36)[0] < 36` is always true, so you'll never enter the second `elif`, that's the problem of your code. – Kevin Fang Sep 26 '18 at 01:50
  • U9, I want it combinations, so eventually, it will go to baa bab bac, and caa, and etc. Kevin, i+=1 makes i increase by 1 so after ~36 iterations it will not be < 36. My issue is with the third piece of code – chriscrutt Sep 26 '18 at 03:39
  • `divmod(i,36)[0]` and `...[1]` are [far less readable, slower](https://stackoverflow.com/questions/30079879/is-divmod-faster-than-using-the-and-operators) ways of doing `i // 36`, `i % d` – smci Sep 26 '18 at 21:23
  • `while 1==1:` is generally written as `while True:` But in your case you initialize `i = 0`, then have a while-True loop, but in all the clauses increment `i += 1`, but it never terminates. You could simply replace all of that with `for i in range(36**2):` or 36**3. (or in this case, `itertools.combinations`) – smci Sep 26 '18 at 21:29

1 Answers1

2

There's no need to use a dict to hold the base digits, we can just put them into a string:

alph = '0123456789abcdefghijlmnopqrstuvwxyz!'

We can get the correct digits by doing the division with remainder in a loop. If the input number is zero, the loop won't produce any digits, so we handle that as a special case. This code will work with a base_digits string of any length, but I'll just use a short string to keep the output short. This code works correctly on Python 2 and Python 3.

from __future__ import print_function

def int_to_base(n, base_digits):
    if n == 0:
        return base_digits[0]
    base = len(base_digits)
    digits = []
    # Build a list of digits in reverse order
    while n:
        n, r = divmod(n, base)
        digits.append(base_digits[r])
    # Reverse the digits and join them into a string
    return ''.join(digits[::-1])

base_digits = '0ab'
for i in range(28):
    print(i, int_to_base(i, base_digits))

output

0 0
1 a
2 b
3 a0
4 aa
5 ab
6 b0
7 ba
8 bb
9 a00
10 a0a
11 a0b
12 aa0
13 aaa
14 aab
15 ab0
16 aba
17 abb
18 b00
19 b0a
20 b0b
21 ba0
22 baa
23 bab
24 bb0
25 bba
26 bbb
27 a000

Another way to do this is to create a generator that counts using the base digits. You can loop over the generator in a for loop, or fetch its next value using the next function.

def base_counter(base_digits):
    """ An infinite iterator that counts using base_digits as its digits """
    base = len(base_digits)
    digits = [0]
    while True:
        yield ''.join([base_digits[d] for d in reversed(digits)])
        digits[0] += 1
        pos = 0
        while digits[pos] == base:
            digits[pos] = 0
            pos += 1
            if pos == len(digits):
                digits.append(1)
            else:
                digits[pos] += 1

base_digits = '0ab'
counter = base_counter(base_digits)
for i, v in enumerate(counter):
    print(i, v)
    if i == 27:
        break
print('next', next(counter))

This produces the same output as the previous version, and then it prints

next a00a
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182