1

In python 3, I have a variable length list, where each element of the list is a variable length string. Something like this

['TO', 'G', 'ZDO', 'DEO', 'SGT', 'D', 'Z', 'FT', 'OV']

and I want to iterate over every possible combination of words where the letters that make up the word are from the strings in the list, and the length of the word is the same as the length of the list. So something like this

TGZDSDZFO
TGZDSDZFV
TGZDSDZTO
...
OGOOTDZTO
OGOOTDZTV

I am having trouble coming up with a generic solution for n-sized list.

  • How do you know how many characters to extract for every string in the list – Tim Dec 16 '14 at 18:58
  • Time, I want one character at a time from each string. Each string in the list contains the possible characters that make up the word at that position in the word. – Walter Anderson Dec 16 '14 at 18:59

3 Answers3

8
>>> (''.join(s) for s in itertools.product(*['TO', 'G', 'ZDO', 'DEO', 'SGT', 'D', 'Z', 'FT', 'OV']))
<generator object <genexpr> at 0x7f2a46468f00>
>>> # to demonstrate:
... 
>>> list(itertools.islice((''.join(s) for s in itertools.product(*['TO', 'G', 'ZDO', 'DEO', 'SGT', 'D', 'Z', 'FT', 'OV'])), 3))
['TGZDSDZFO', 'TGZDSDZFV', 'TGZDSDZTO']
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 3
    `itertools.product()` does the product of all of its arguments. The `*` separates the list into separate arguments for the function call. `''.join()` joins with no separators. The rest is just a normal genex. – Ignacio Vazquez-Abrams Dec 16 '14 at 19:04
2

As others have suggested, itertools is perhaps the simplest/easiest way to solve this. If you are looking to write your own algorithm however (i.e. reimplement what itertools does under the hood), then take a look at this:

def allPerms(L, sofar=''):
    if not L:
        print(sofar)
    else:
        for char in L[0]:
            allPerms(L[1:], sofar+char)

Output:

In [97]: L = ['TO', 'G', 'ZDO', 'DEO', 'SGT', 'D', 'Z', 'FT', 'OV']

In [98]: allPerms(L)
TGZDSDZFO
TGZDSDZFV
TGZDSDZTO
TGZDSDZTV
TGZDGDZFO
TGZDGDZFV
TGZDGDZTO
TGZDGDZTV
TGZDTDZFO
TGZDTDZFV
TGZDTDZTO
TGZDTDZTV
TGZESDZFO
TGZESDZFV
TGZESDZTO
TGZESDZTV
TGZEGDZFO
TGZEGDZFV
TGZEGDZTO
TGZEGDZTV
--- truncated ---

EDIT:

As @njzk2 points out, python3's yield-from does a fantastic job of making the output usable:

def allPerms(L, sofar=''):
    if not L: yield sofar
    else:
        for char in L[0]: yield from allPerms(L[1:], sofar+char)

Output:

In [118]: for i in allPerms(L): print(i)
TGZDSDZFO
TGZDSDZFV
TGZDSDZTO
TGZDSDZTV
TGZDGDZFO
TGZDGDZFV
TGZDGDZTO
TGZDGDZTV
TGZDTDZFO
TGZDTDZFV
TGZDTDZTO
TGZDTDZTV
TGZESDZFO
TGZESDZFV
TGZESDZTO
TGZESDZTV
TGZEGDZFO
TGZEGDZFV
TGZEGDZTO
TGZEGDZTV
TGZETDZFO
TGZETDZFV
TGZETDZTO
--- truncated ---
Community
  • 1
  • 1
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
  • `yield` would be nicer than `print`, as it would allow to use the output. – njzk2 Dec 16 '14 at 19:13
  • 1
    I am trying as well, no luck so far. I'll let you know when I get there. – njzk2 Dec 16 '14 at 19:17
  • this http://stackoverflow.com/a/6755918/671543 explains that before python 3, we need to re-iterate to transmit the yield, but in python 3 we can use `yield from`, which yields successively all items. python2 -> `yield sofar` + `for value in allPerms(L[1:], sofar+char): yield value`, python3 -> `yield sofar` + `yield from allPerms(L[1:], sofar+char)` – njzk2 Dec 16 '14 at 19:21
-4

you could use the itertools module to create the permutations of your desired length. combine all the workds to one string and use it in the permutations function

lst = ['TO', 'G', 'ZDO', 'DEO', 'SGT', 'D', 'Z', 'FT', 'OV']
length = len(lst)

combined = ''.join(lst)
all_perms = itertools.permutations(combined, length)
#this will give you something like [('T', 'O', ...), (...),]

print ([''.join(x) for x in all_perms])
srj
  • 9,591
  • 2
  • 23
  • 27