0

It's been a while since I've used Python and needed to do something like this. But what I'd like to do is loop through every unique four-character alphabetical sequence. For example:

aaaa aaab ... aaaz ... abcd ... zzzz

import string
az = string.ascii_lowercase
for c1 in az:
  for c2 in az:
    for c3 in az:
      for c4 in az:
        print(c1 + c2 + c3 + c4)

Is there a more efficient and or prettier way to do this?

oldboy
  • 5,729
  • 6
  • 38
  • 86

2 Answers2

1

I think itertools.product() is what you are looking for. If you pass it string.ascii_lowercase and the number of characters you want, it should do the rest:

from itertools import product
import string
[''.join(s) for s in product(string.ascii_lowercase, repeat=4)]

--

['aaaa',
 'aaab',
 'aaac',
 'aaad',
 'aaae',
 'aaaf',
 'aaag',
 'aaah',
 'aaai',
 ...
 'zzzq',
 'zzzr',
 'zzzs',
 'zzzt',
 'zzzu',
 'zzzv',
 'zzzw',
 'zzzx',
 'zzzy',
 'zzzz']
Mark
  • 90,562
  • 7
  • 108
  • 148
  • other buddy's comment has me a bit confused. what's the diff between `combinations` and `product`? `combination` is only tuples? – oldboy Jul 07 '19 at 23:27
  • weird how i cant just `import itertools` as a whole – oldboy Jul 07 '19 at 23:28
  • Combinations won't give you all the different orders of letters such as `aaab` and `baaa` – Mark Jul 07 '19 at 23:30
  • also, any idea if this is more efficient than nesting loops? – oldboy Jul 07 '19 at 23:30
  • sooo `combinations` only spits out combinations whereby each character is unique instead of the whole string or? – oldboy Jul 07 '19 at 23:31
  • No, you can use `combinations_with_replacement` and get duplicates, but it's not the same. It's easier to see in a small list. Compare: `[''.join(s) for s in combinations_with_replacement(['1', '2', '3'],2)]` with `[''.join(s) for s in product(['1', '2', '3'], repeat=2)]` – Mark Jul 07 '19 at 23:32
  • Not sure about the performance — I've always assumed itertools was made to perform well, but I've never tested it. There's a [thread here](https://stackoverflow.com/questions/15477314/performance-of-library-itertools-compared-to-python-code) that might be useful. – Mark Jul 07 '19 at 23:34
  • kk ill compare em right now. ah ok, thats kinda what i figured it would do. – oldboy Jul 07 '19 at 23:41
0

If you need to roll your own, then you can iterate from 0 to 26⁴ - 1, and convert to a number base 26 with your own digit translation.

def baseN(number, base, digits):
    return ((number == 0) and digits[0]) or (baseN(number // base, base, digits) + digits[number % base])

digits = "abcdefghijklmnopqrstuvwxyz"
base = len(digits)
length = 4

for number in range(base ** length):
    print((digits[0] * (length - 1) + baseN(number, base, digits))[-length:])
  • nested loops is a lot more readable. would that be more efficient than using nested loops? – oldboy Jul 08 '19 at 00:02
  • To change the number of digits would be easier in mine, just change the `4`s to `5`s or whatever, easy to make this generic for any length. Whereas with nested loops you have to add or remove a level and revise the summation. –  Jul 08 '19 at 00:51