You can create iterables for keeping the possible alternatives for each place:

firsts = ['ph', 'sd', 'nn', 'mm', 'gh']
seconds = fourths = ['a', 'e', 'i', 'o', 'u', 'y', 'rc']
thirds = 'b'
fifths = 'a'

List comprehension

You could use a list comprehension:

print [''.join((first, second, third, fourth, fifth))
       for first in firsts
       for second in seconds
       for third in thirds
       for fourth in fourths
       for fifth in fifths]

Output

['phabaa', 'phabea', 'phabia', 'phaboa', 'phabua', 'phabya', 'phabrca', 'phebaa', 'phebea', 'phebia', 'pheboa', 'phebua', 'phebya', 'phebrca', 'phibaa', 'phibea', 'phibia', 'phiboa', 'phibua', 'phibya', 'phibrca', 'phobaa', 'phobea', 'phobia', 'phoboa', 'phobua', 'phobya', 'phobrca', 'phubaa', 'phubea', 'phubia', 'phuboa', 'phubua', 'phubya', 'phubrca', 'phybaa', 'phybea', 'phybia', 'phyboa', 'phybua', 'phybya', 'phybrca', 'phrcbaa', 'phrcbea', 'phrcbia', 'phrcboa', 'phrcbua', 'phrcbya', 'phrcbrca', 'sdabaa', 'sdabea', 'sdabia', 'sdaboa', 'sdabua', 'sdabya', 'sdabrca', 'sdebaa', 'sdebea', 'sdebia', 'sdeboa', 'sdebua', 'sdebya', 'sdebrca', 'sdibaa', 'sdibea', 'sdibia', 'sdiboa', 'sdibua', 'sdibya', 'sdibrca', 'sdobaa', 'sdobea', 'sdobia', 'sdoboa', 'sdobua', 'sdobya', 'sdobrca', 'sdubaa', 'sdubea', 'sdubia', 'sduboa', 'sdubua', 'sdubya', 'sdubrca', 'sdybaa', 'sdybea', 'sdybia', 'sdyboa', 'sdybua', 'sdybya', 'sdybrca', 'sdrcbaa', 'sdrcbea', 'sdrcbia', 'sdrcboa', 'sdrcbua', 'sdrcbya', 'sdrcbrca', 'nnabaa', 'nnabea', 'nnabia', 'nnaboa', 'nnabua', 'nnabya', 'nnabrca', 'nnebaa', 'nnebea', 'nnebia', 'nneboa', 'nnebua', 'nnebya', 'nnebrca', 'nnibaa', 'nnibea', 'nnibia', 'nniboa', 'nnibua', 'nnibya', 'nnibrca', 'nnobaa', 'nnobea', 'nnobia', 'nnoboa', 'nnobua', 'nnobya', 'nnobrca', 'nnubaa', 'nnubea', 'nnubia', 'nnuboa', 'nnubua', 'nnubya', 'nnubrca', 'nnybaa', 'nnybea', 'nnybia', 'nnyboa', 'nnybua', 'nnybya', 'nnybrca', 'nnrcbaa', 'nnrcbea', 'nnrcbia', 'nnrcboa', 'nnrcbua', 'nnrcbya', 'nnrcbrca', 'mmabaa', 'mmabea', 'mmabia', 'mmaboa', 'mmabua', 'mmabya', 'mmabrca', 'mmebaa', 'mmebea', 'mmebia', 'mmeboa', 'mmebua', 'mmebya', 'mmebrca', 'mmibaa', 'mmibea', 'mmibia', 'mmiboa', 'mmibua', 'mmibya', 'mmibrca', 'mmobaa', 'mmobea', 'mmobia', 'mmoboa', 'mmobua', 'mmobya', 'mmobrca', 'mmubaa', 'mmubea', 'mmubia', 'mmuboa', 'mmubua', 'mmubya', 'mmubrca', 'mmybaa', 'mmybea', 'mmybia', 'mmyboa', 'mmybua', 'mmybya', 'mmybrca', 'mmrcbaa', 'mmrcbea', 'mmrcbia', 'mmrcboa', 'mmrcbua', 'mmrcbya', 'mmrcbrca', 'ghabaa', 'ghabea', 'ghabia', 'ghaboa', 'ghabua', 'ghabya', 'ghabrca', 'ghebaa', 'ghebea', 'ghebia', 'gheboa', 'ghebua', 'ghebya', 'ghebrca', 'ghibaa', 'ghibea', 'ghibia', 'ghiboa', 'ghibua', 'ghibya', 'ghibrca', 'ghobaa', 'ghobea', 'ghobia', 'ghoboa', 'ghobua', 'ghobya', 'ghobrca', 'ghubaa', 'ghubea', 'ghubia', 'ghuboa', 'ghubua', 'ghubya', 'ghubrca', 'ghybaa', 'ghybea', 'ghybia', 'ghyboa', 'ghybua', 'ghybya', 'ghybrca', 'ghrcbaa', 'ghrcbea', 'ghrcbia', 'ghrcboa', 'ghrcbua', 'ghrcbya', 'ghrcbrca']

itertools.product

Another nice way is to use itertools.product:

from itertools import product
print [''.join(letters)
       for letters in product(firsts, seconds, thirds, fourths, fifths)]

Output

['phabaa', 'phabea', 'phabia', 'phaboa', 'phabua', 'phabya', 'phabrca', 'phebaa', 'phebea', 'phebia', 'pheboa', 'phebua', 'phebya', 'phebrca', 'phibaa', 'phibea', 'phibia', 'phiboa', 'phibua', 'phibya', 'phibrca', 'phobaa', 'phobea', 'phobia', 'phoboa', 'phobua', 'phobya', 'phobrca', 'phubaa', 'phubea', 'phubia', 'phuboa', 'phubua', 'phubya', 'phubrca', 'phybaa', 'phybea', 'phybia', 'phyboa', 'phybua', 'phybya', 'phybrca', 'phrcbaa', 'phrcbea', 'phrcbia', 'phrcboa', 'phrcbua', 'phrcbya', 'phrcbrca', 'sdabaa', 'sdabea', 'sdabia', 'sdaboa', 'sdabua', 'sdabya', 'sdabrca', 'sdebaa', 'sdebea', 'sdebia', 'sdeboa', 'sdebua', 'sdebya', 'sdebrca', 'sdibaa', 'sdibea', 'sdibia', 'sdiboa', 'sdibua', 'sdibya', 'sdibrca', 'sdobaa', 'sdobea', 'sdobia', 'sdoboa', 'sdobua', 'sdobya', 'sdobrca', 'sdubaa', 'sdubea', 'sdubia', 'sduboa', 'sdubua', 'sdubya', 'sdubrca', 'sdybaa', 'sdybea', 'sdybia', 'sdyboa', 'sdybua', 'sdybya', 'sdybrca', 'sdrcbaa', 'sdrcbea', 'sdrcbia', 'sdrcboa', 'sdrcbua', 'sdrcbya', 'sdrcbrca', 'nnabaa', 'nnabea', 'nnabia', 'nnaboa', 'nnabua', 'nnabya', 'nnabrca', 'nnebaa', 'nnebea', 'nnebia', 'nneboa', 'nnebua', 'nnebya', 'nnebrca', 'nnibaa', 'nnibea', 'nnibia', 'nniboa', 'nnibua', 'nnibya', 'nnibrca', 'nnobaa', 'nnobea', 'nnobia', 'nnoboa', 'nnobua', 'nnobya', 'nnobrca', 'nnubaa', 'nnubea', 'nnubia', 'nnuboa', 'nnubua', 'nnubya', 'nnubrca', 'nnybaa', 'nnybea', 'nnybia', 'nnyboa', 'nnybua', 'nnybya', 'nnybrca', 'nnrcbaa', 'nnrcbea', 'nnrcbia', 'nnrcboa', 'nnrcbua', 'nnrcbya', 'nnrcbrca', 'mmabaa', 'mmabea', 'mmabia', 'mmaboa', 'mmabua', 'mmabya', 'mmabrca', 'mmebaa', 'mmebea', 'mmebia', 'mmeboa', 'mmebua', 'mmebya', 'mmebrca', 'mmibaa', 'mmibea', 'mmibia', 'mmiboa', 'mmibua', 'mmibya', 'mmibrca', 'mmobaa', 'mmobea', 'mmobia', 'mmoboa', 'mmobua', 'mmobya', 'mmobrca', 'mmubaa', 'mmubea', 'mmubia', 'mmuboa', 'mmubua', 'mmubya', 'mmubrca', 'mmybaa', 'mmybea', 'mmybia', 'mmyboa', 'mmybua', 'mmybya', 'mmybrca', 'mmrcbaa', 'mmrcbea', 'mmrcbia', 'mmrcboa', 'mmrcbua', 'mmrcbya', 'mmrcbrca', 'ghabaa', 'ghabea', 'ghabia', 'ghaboa', 'ghabua', 'ghabya', 'ghabrca', 'ghebaa', 'ghebea', 'ghebia', 'gheboa', 'ghebua', 'ghebya', 'ghebrca', 'ghibaa', 'ghibea', 'ghibia', 'ghiboa', 'ghibua', 'ghibya', 'ghibrca', 'ghobaa', 'ghobea', 'ghobia', 'ghoboa', 'ghobua', 'ghobya', 'ghobrca', 'ghubaa', 'ghubea', 'ghubia', 'ghuboa', 'ghubua', 'ghubya', 'ghubrca', 'ghybaa', 'ghybea', 'ghybia', 'ghyboa', 'ghybua', 'ghybya', 'ghybrca', 'ghrcbaa', 'ghrcbea', 'ghrcbia', 'ghrcboa', 'ghrcbua', 'ghrcbya', 'ghrcbrca']

The nice part of this second solution is that you don't have to hardcode the logic, and if needed you could just replace the iterables with others, even when you have more or less places:

from itertools import product

def genwords(*iterables):
    return [''.join(letters) for letters in product(*iterables)]

print genwords(firsts, seconds, thirds, fourths, fifths)
print genwords('123', 'abc')

Output

['phabaa', 'phabea', 'phabia', 'phaboa', 'phabua', 'phabya', 'phabrca', 'phebaa', 'phebea', 'phebia', 'pheboa', 'phebua', 'phebya', 'phebrca', 'phibaa', 'phibea', 'phibia', 'phiboa', 'phibua', 'phibya', 'phibrca', 'phobaa', 'phobea', 'phobia', 'phoboa', 'phobua', 'phobya', 'phobrca', 'phubaa', 'phubea', 'phubia', 'phuboa', 'phubua', 'phubya', 'phubrca', 'phybaa', 'phybea', 'phybia', 'phyboa', 'phybua', 'phybya', 'phybrca', 'phrcbaa', 'phrcbea', 'phrcbia', 'phrcboa', 'phrcbua', 'phrcbya', 'phrcbrca', 'sdabaa', 'sdabea', 'sdabia', 'sdaboa', 'sdabua', 'sdabya', 'sdabrca', 'sdebaa', 'sdebea', 'sdebia', 'sdeboa', 'sdebua', 'sdebya', 'sdebrca', 'sdibaa', 'sdibea', 'sdibia', 'sdiboa', 'sdibua', 'sdibya', 'sdibrca', 'sdobaa', 'sdobea', 'sdobia', 'sdoboa', 'sdobua', 'sdobya', 'sdobrca', 'sdubaa', 'sdubea', 'sdubia', 'sduboa', 'sdubua', 'sdubya', 'sdubrca', 'sdybaa', 'sdybea', 'sdybia', 'sdyboa', 'sdybua', 'sdybya', 'sdybrca', 'sdrcbaa', 'sdrcbea', 'sdrcbia', 'sdrcboa', 'sdrcbua', 'sdrcbya', 'sdrcbrca', 'nnabaa', 'nnabea', 'nnabia', 'nnaboa', 'nnabua', 'nnabya', 'nnabrca', 'nnebaa', 'nnebea', 'nnebia', 'nneboa', 'nnebua', 'nnebya', 'nnebrca', 'nnibaa', 'nnibea', 'nnibia', 'nniboa', 'nnibua', 'nnibya', 'nnibrca', 'nnobaa', 'nnobea', 'nnobia', 'nnoboa', 'nnobua', 'nnobya', 'nnobrca', 'nnubaa', 'nnubea', 'nnubia', 'nnuboa', 'nnubua', 'nnubya', 'nnubrca', 'nnybaa', 'nnybea', 'nnybia', 'nnyboa', 'nnybua', 'nnybya', 'nnybrca', 'nnrcbaa', 'nnrcbea', 'nnrcbia', 'nnrcboa', 'nnrcbua', 'nnrcbya', 'nnrcbrca', 'mmabaa', 'mmabea', 'mmabia', 'mmaboa', 'mmabua', 'mmabya', 'mmabrca', 'mmebaa', 'mmebea', 'mmebia', 'mmeboa', 'mmebua', 'mmebya', 'mmebrca', 'mmibaa', 'mmibea', 'mmibia', 'mmiboa', 'mmibua', 'mmibya', 'mmibrca', 'mmobaa', 'mmobea', 'mmobia', 'mmoboa', 'mmobua', 'mmobya', 'mmobrca', 'mmubaa', 'mmubea', 'mmubia', 'mmuboa', 'mmubua', 'mmubya', 'mmubrca', 'mmybaa', 'mmybea', 'mmybia', 'mmyboa', 'mmybua', 'mmybya', 'mmybrca', 'mmrcbaa', 'mmrcbea', 'mmrcbia', 'mmrcboa', 'mmrcbua', 'mmrcbya', 'mmrcbrca', 'ghabaa', 'ghabea', 'ghabia', 'ghaboa', 'ghabua', 'ghabya', 'ghabrca', 'ghebaa', 'ghebea', 'ghebia', 'gheboa', 'ghebua', 'ghebya', 'ghebrca', 'ghibaa', 'ghibea', 'ghibia', 'ghiboa', 'ghibua', 'ghibya', 'ghibrca', 'ghobaa', 'ghobea', 'ghobia', 'ghoboa', 'ghobua', 'ghobya', 'ghobrca', 'ghubaa', 'ghubea', 'ghubia', 'ghuboa', 'ghubua', 'ghubya', 'ghubrca', 'ghybaa', 'ghybea', 'ghybia', 'ghyboa', 'ghybua', 'ghybya', 'ghybrca', 'ghrcbaa', 'ghrcbea', 'ghrcbia', 'ghrcboa', 'ghrcbua', 'ghrcbya', 'ghrcbrca']
['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']
Answer from enrico.bacis on Stack Overflow
Top answer
1 of 2
4

You can create iterables for keeping the possible alternatives for each place:

firsts = ['ph', 'sd', 'nn', 'mm', 'gh']
seconds = fourths = ['a', 'e', 'i', 'o', 'u', 'y', 'rc']
thirds = 'b'
fifths = 'a'

List comprehension

You could use a list comprehension:

print [''.join((first, second, third, fourth, fifth))
       for first in firsts
       for second in seconds
       for third in thirds
       for fourth in fourths
       for fifth in fifths]

Output

['phabaa', 'phabea', 'phabia', 'phaboa', 'phabua', 'phabya', 'phabrca', 'phebaa', 'phebea', 'phebia', 'pheboa', 'phebua', 'phebya', 'phebrca', 'phibaa', 'phibea', 'phibia', 'phiboa', 'phibua', 'phibya', 'phibrca', 'phobaa', 'phobea', 'phobia', 'phoboa', 'phobua', 'phobya', 'phobrca', 'phubaa', 'phubea', 'phubia', 'phuboa', 'phubua', 'phubya', 'phubrca', 'phybaa', 'phybea', 'phybia', 'phyboa', 'phybua', 'phybya', 'phybrca', 'phrcbaa', 'phrcbea', 'phrcbia', 'phrcboa', 'phrcbua', 'phrcbya', 'phrcbrca', 'sdabaa', 'sdabea', 'sdabia', 'sdaboa', 'sdabua', 'sdabya', 'sdabrca', 'sdebaa', 'sdebea', 'sdebia', 'sdeboa', 'sdebua', 'sdebya', 'sdebrca', 'sdibaa', 'sdibea', 'sdibia', 'sdiboa', 'sdibua', 'sdibya', 'sdibrca', 'sdobaa', 'sdobea', 'sdobia', 'sdoboa', 'sdobua', 'sdobya', 'sdobrca', 'sdubaa', 'sdubea', 'sdubia', 'sduboa', 'sdubua', 'sdubya', 'sdubrca', 'sdybaa', 'sdybea', 'sdybia', 'sdyboa', 'sdybua', 'sdybya', 'sdybrca', 'sdrcbaa', 'sdrcbea', 'sdrcbia', 'sdrcboa', 'sdrcbua', 'sdrcbya', 'sdrcbrca', 'nnabaa', 'nnabea', 'nnabia', 'nnaboa', 'nnabua', 'nnabya', 'nnabrca', 'nnebaa', 'nnebea', 'nnebia', 'nneboa', 'nnebua', 'nnebya', 'nnebrca', 'nnibaa', 'nnibea', 'nnibia', 'nniboa', 'nnibua', 'nnibya', 'nnibrca', 'nnobaa', 'nnobea', 'nnobia', 'nnoboa', 'nnobua', 'nnobya', 'nnobrca', 'nnubaa', 'nnubea', 'nnubia', 'nnuboa', 'nnubua', 'nnubya', 'nnubrca', 'nnybaa', 'nnybea', 'nnybia', 'nnyboa', 'nnybua', 'nnybya', 'nnybrca', 'nnrcbaa', 'nnrcbea', 'nnrcbia', 'nnrcboa', 'nnrcbua', 'nnrcbya', 'nnrcbrca', 'mmabaa', 'mmabea', 'mmabia', 'mmaboa', 'mmabua', 'mmabya', 'mmabrca', 'mmebaa', 'mmebea', 'mmebia', 'mmeboa', 'mmebua', 'mmebya', 'mmebrca', 'mmibaa', 'mmibea', 'mmibia', 'mmiboa', 'mmibua', 'mmibya', 'mmibrca', 'mmobaa', 'mmobea', 'mmobia', 'mmoboa', 'mmobua', 'mmobya', 'mmobrca', 'mmubaa', 'mmubea', 'mmubia', 'mmuboa', 'mmubua', 'mmubya', 'mmubrca', 'mmybaa', 'mmybea', 'mmybia', 'mmyboa', 'mmybua', 'mmybya', 'mmybrca', 'mmrcbaa', 'mmrcbea', 'mmrcbia', 'mmrcboa', 'mmrcbua', 'mmrcbya', 'mmrcbrca', 'ghabaa', 'ghabea', 'ghabia', 'ghaboa', 'ghabua', 'ghabya', 'ghabrca', 'ghebaa', 'ghebea', 'ghebia', 'gheboa', 'ghebua', 'ghebya', 'ghebrca', 'ghibaa', 'ghibea', 'ghibia', 'ghiboa', 'ghibua', 'ghibya', 'ghibrca', 'ghobaa', 'ghobea', 'ghobia', 'ghoboa', 'ghobua', 'ghobya', 'ghobrca', 'ghubaa', 'ghubea', 'ghubia', 'ghuboa', 'ghubua', 'ghubya', 'ghubrca', 'ghybaa', 'ghybea', 'ghybia', 'ghyboa', 'ghybua', 'ghybya', 'ghybrca', 'ghrcbaa', 'ghrcbea', 'ghrcbia', 'ghrcboa', 'ghrcbua', 'ghrcbya', 'ghrcbrca']

itertools.product

Another nice way is to use itertools.product:

from itertools import product
print [''.join(letters)
       for letters in product(firsts, seconds, thirds, fourths, fifths)]

Output

['phabaa', 'phabea', 'phabia', 'phaboa', 'phabua', 'phabya', 'phabrca', 'phebaa', 'phebea', 'phebia', 'pheboa', 'phebua', 'phebya', 'phebrca', 'phibaa', 'phibea', 'phibia', 'phiboa', 'phibua', 'phibya', 'phibrca', 'phobaa', 'phobea', 'phobia', 'phoboa', 'phobua', 'phobya', 'phobrca', 'phubaa', 'phubea', 'phubia', 'phuboa', 'phubua', 'phubya', 'phubrca', 'phybaa', 'phybea', 'phybia', 'phyboa', 'phybua', 'phybya', 'phybrca', 'phrcbaa', 'phrcbea', 'phrcbia', 'phrcboa', 'phrcbua', 'phrcbya', 'phrcbrca', 'sdabaa', 'sdabea', 'sdabia', 'sdaboa', 'sdabua', 'sdabya', 'sdabrca', 'sdebaa', 'sdebea', 'sdebia', 'sdeboa', 'sdebua', 'sdebya', 'sdebrca', 'sdibaa', 'sdibea', 'sdibia', 'sdiboa', 'sdibua', 'sdibya', 'sdibrca', 'sdobaa', 'sdobea', 'sdobia', 'sdoboa', 'sdobua', 'sdobya', 'sdobrca', 'sdubaa', 'sdubea', 'sdubia', 'sduboa', 'sdubua', 'sdubya', 'sdubrca', 'sdybaa', 'sdybea', 'sdybia', 'sdyboa', 'sdybua', 'sdybya', 'sdybrca', 'sdrcbaa', 'sdrcbea', 'sdrcbia', 'sdrcboa', 'sdrcbua', 'sdrcbya', 'sdrcbrca', 'nnabaa', 'nnabea', 'nnabia', 'nnaboa', 'nnabua', 'nnabya', 'nnabrca', 'nnebaa', 'nnebea', 'nnebia', 'nneboa', 'nnebua', 'nnebya', 'nnebrca', 'nnibaa', 'nnibea', 'nnibia', 'nniboa', 'nnibua', 'nnibya', 'nnibrca', 'nnobaa', 'nnobea', 'nnobia', 'nnoboa', 'nnobua', 'nnobya', 'nnobrca', 'nnubaa', 'nnubea', 'nnubia', 'nnuboa', 'nnubua', 'nnubya', 'nnubrca', 'nnybaa', 'nnybea', 'nnybia', 'nnyboa', 'nnybua', 'nnybya', 'nnybrca', 'nnrcbaa', 'nnrcbea', 'nnrcbia', 'nnrcboa', 'nnrcbua', 'nnrcbya', 'nnrcbrca', 'mmabaa', 'mmabea', 'mmabia', 'mmaboa', 'mmabua', 'mmabya', 'mmabrca', 'mmebaa', 'mmebea', 'mmebia', 'mmeboa', 'mmebua', 'mmebya', 'mmebrca', 'mmibaa', 'mmibea', 'mmibia', 'mmiboa', 'mmibua', 'mmibya', 'mmibrca', 'mmobaa', 'mmobea', 'mmobia', 'mmoboa', 'mmobua', 'mmobya', 'mmobrca', 'mmubaa', 'mmubea', 'mmubia', 'mmuboa', 'mmubua', 'mmubya', 'mmubrca', 'mmybaa', 'mmybea', 'mmybia', 'mmyboa', 'mmybua', 'mmybya', 'mmybrca', 'mmrcbaa', 'mmrcbea', 'mmrcbia', 'mmrcboa', 'mmrcbua', 'mmrcbya', 'mmrcbrca', 'ghabaa', 'ghabea', 'ghabia', 'ghaboa', 'ghabua', 'ghabya', 'ghabrca', 'ghebaa', 'ghebea', 'ghebia', 'gheboa', 'ghebua', 'ghebya', 'ghebrca', 'ghibaa', 'ghibea', 'ghibia', 'ghiboa', 'ghibua', 'ghibya', 'ghibrca', 'ghobaa', 'ghobea', 'ghobia', 'ghoboa', 'ghobua', 'ghobya', 'ghobrca', 'ghubaa', 'ghubea', 'ghubia', 'ghuboa', 'ghubua', 'ghubya', 'ghubrca', 'ghybaa', 'ghybea', 'ghybia', 'ghyboa', 'ghybua', 'ghybya', 'ghybrca', 'ghrcbaa', 'ghrcbea', 'ghrcbia', 'ghrcboa', 'ghrcbua', 'ghrcbya', 'ghrcbrca']

The nice part of this second solution is that you don't have to hardcode the logic, and if needed you could just replace the iterables with others, even when you have more or less places:

from itertools import product

def genwords(*iterables):
    return [''.join(letters) for letters in product(*iterables)]

print genwords(firsts, seconds, thirds, fourths, fifths)
print genwords('123', 'abc')

Output

['phabaa', 'phabea', 'phabia', 'phaboa', 'phabua', 'phabya', 'phabrca', 'phebaa', 'phebea', 'phebia', 'pheboa', 'phebua', 'phebya', 'phebrca', 'phibaa', 'phibea', 'phibia', 'phiboa', 'phibua', 'phibya', 'phibrca', 'phobaa', 'phobea', 'phobia', 'phoboa', 'phobua', 'phobya', 'phobrca', 'phubaa', 'phubea', 'phubia', 'phuboa', 'phubua', 'phubya', 'phubrca', 'phybaa', 'phybea', 'phybia', 'phyboa', 'phybua', 'phybya', 'phybrca', 'phrcbaa', 'phrcbea', 'phrcbia', 'phrcboa', 'phrcbua', 'phrcbya', 'phrcbrca', 'sdabaa', 'sdabea', 'sdabia', 'sdaboa', 'sdabua', 'sdabya', 'sdabrca', 'sdebaa', 'sdebea', 'sdebia', 'sdeboa', 'sdebua', 'sdebya', 'sdebrca', 'sdibaa', 'sdibea', 'sdibia', 'sdiboa', 'sdibua', 'sdibya', 'sdibrca', 'sdobaa', 'sdobea', 'sdobia', 'sdoboa', 'sdobua', 'sdobya', 'sdobrca', 'sdubaa', 'sdubea', 'sdubia', 'sduboa', 'sdubua', 'sdubya', 'sdubrca', 'sdybaa', 'sdybea', 'sdybia', 'sdyboa', 'sdybua', 'sdybya', 'sdybrca', 'sdrcbaa', 'sdrcbea', 'sdrcbia', 'sdrcboa', 'sdrcbua', 'sdrcbya', 'sdrcbrca', 'nnabaa', 'nnabea', 'nnabia', 'nnaboa', 'nnabua', 'nnabya', 'nnabrca', 'nnebaa', 'nnebea', 'nnebia', 'nneboa', 'nnebua', 'nnebya', 'nnebrca', 'nnibaa', 'nnibea', 'nnibia', 'nniboa', 'nnibua', 'nnibya', 'nnibrca', 'nnobaa', 'nnobea', 'nnobia', 'nnoboa', 'nnobua', 'nnobya', 'nnobrca', 'nnubaa', 'nnubea', 'nnubia', 'nnuboa', 'nnubua', 'nnubya', 'nnubrca', 'nnybaa', 'nnybea', 'nnybia', 'nnyboa', 'nnybua', 'nnybya', 'nnybrca', 'nnrcbaa', 'nnrcbea', 'nnrcbia', 'nnrcboa', 'nnrcbua', 'nnrcbya', 'nnrcbrca', 'mmabaa', 'mmabea', 'mmabia', 'mmaboa', 'mmabua', 'mmabya', 'mmabrca', 'mmebaa', 'mmebea', 'mmebia', 'mmeboa', 'mmebua', 'mmebya', 'mmebrca', 'mmibaa', 'mmibea', 'mmibia', 'mmiboa', 'mmibua', 'mmibya', 'mmibrca', 'mmobaa', 'mmobea', 'mmobia', 'mmoboa', 'mmobua', 'mmobya', 'mmobrca', 'mmubaa', 'mmubea', 'mmubia', 'mmuboa', 'mmubua', 'mmubya', 'mmubrca', 'mmybaa', 'mmybea', 'mmybia', 'mmyboa', 'mmybua', 'mmybya', 'mmybrca', 'mmrcbaa', 'mmrcbea', 'mmrcbia', 'mmrcboa', 'mmrcbua', 'mmrcbya', 'mmrcbrca', 'ghabaa', 'ghabea', 'ghabia', 'ghaboa', 'ghabua', 'ghabya', 'ghabrca', 'ghebaa', 'ghebea', 'ghebia', 'gheboa', 'ghebua', 'ghebya', 'ghebrca', 'ghibaa', 'ghibea', 'ghibia', 'ghiboa', 'ghibua', 'ghibya', 'ghibrca', 'ghobaa', 'ghobea', 'ghobia', 'ghoboa', 'ghobua', 'ghobya', 'ghobrca', 'ghubaa', 'ghubea', 'ghubia', 'ghuboa', 'ghubua', 'ghubya', 'ghubrca', 'ghybaa', 'ghybea', 'ghybia', 'ghyboa', 'ghybua', 'ghybya', 'ghybrca', 'ghrcbaa', 'ghrcbea', 'ghrcbia', 'ghrcboa', 'ghrcbua', 'ghrcbya', 'ghrcbrca']
['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']
2 of 2
2

I would approach this as follows, using itertools.product in a generator function (to avoid building the whole list unless you absolutely have to):

from itertools import product

def words(definition):
    for t in product(*definition):
        yield "".join(t)

The only trick is providing the definition in an appropriate format; it must be a list of iterables, each of which provides the options for each "letter". This is easy where each option for a letter is a single character:

>>> list(words(["f", "o", "aeiou"]))
['foa', 'foe', 'foi', 'foo', 'fou']

But with your multiple-character letters you will need to supply a list or tuple:

>>> list(words([['ph', 'sd', 'nn', 'mm', 'gh'], 
                ['a', 'e', 'i', 'o', 'u', 'y', 'rc'], 
                'b', 
                ['a', 'e', 'i', 'o', 'u', 'y', 'rc'], 
                'a']))
['phabaa', 'phabea', 'phabia', ..., 'ghrcbya', 'ghrcbrca']

Note that in Python 3.3 onwards, this can be done in a single line with yield from:

def words(definition):
    yield from map("".join, product(*definition))
Discussions

python - Generating words based on a list of letters - Code Review Stack Exchange
The constraints are that there ... in the word, and you can't repeat any letters. Everything works, but the running time is way too long. I'm hoping to get some feedback on how to cut down my running time in O-notation. Also, if you know the running times of the built in function, that would be great. Also, comment if my code style is not what it should be for Python. import itertools from multiprocessing ... More on codereview.stackexchange.com
🌐 codereview.stackexchange.com
August 19, 2012
beginner - Python random word generator that generates a wordlike pronounceable string - Code Review Stack Exchange
This is a random word generator I wrote in Python 3 today, I don't know how many Python implemetations of this exist, but this is my first try and it is completely working. It returns a random word like string that is pronounceable (most likely pronounceable), I used some English letter frequency ... More on codereview.stackexchange.com
🌐 codereview.stackexchange.com
May 30, 2021
python - Generate readable English words from given letters - Code Review Stack Exchange
I was redirected from StackOverflow to your community in hope to get some help and improve my script. The script receives letters as input and generates possible words, then extracts readable words... More on codereview.stackexchange.com
🌐 codereview.stackexchange.com
May 16, 2022
Created a random word generator program, looking for criticism
Read the sidebar for how to post your code. Alternatively, upload to http://codepad.org/?lang=Python I'm not going to critique your actual code until it is more readable, but as for your algorithm, I think you would do better to include dipthongs (e.g. ou) as vowels and digraphs (e.g. sh) and blends (e.g. pt) as consonants. I recommend this because words aren't really strings of letters, but strings of syllables, which can be more closely estimated than simply in terms of vowels and consonants. As an example, just alternating consonants and vowels will always produce words like Pokawy or Renika, which tend to have a very distinctive and somewhat artificial sound (although words generated this way can be very similar to those of the native Hawaiian language), while including dipthongs, blends, and digraphs can produce words more along the lines of eptia or temmish. That being said, this still isn't a great system. Of course, depending on what real-life language you are trying to emulate (if any) your system is going to have to be different. But even assuming you're trying to make English-sounding words, improvements can certainly be made. For example, the frequency of certain sounds coming after others more closely matches those from a dictionary. But those innovations are up to you to implement, should you desire. You could even look into having suffix and prefix generators, really the possibilities are endless. This might be useful: http://school.judsonisd.org/webpages/cbianco/readinghelp.cfm?subpage=23376 More on reddit.com
🌐 r/Python
4
0
August 24, 2015
Top answer
1 of 8
122

Reading a local word list

If you're doing this repeatedly, I would download it locally and pull from the local file. *nix users can use /usr/share/dict/words.

Example:

word_file = "/usr/share/dict/words"
WORDS = open(word_file).read().splitlines()

Pulling from a remote dictionary

If you want to pull from a remote dictionary, here are a couple of ways. The requests library makes this really easy (you'll have to pip install requests):

import requests

word_site = "https://www.mit.edu/~ecprice/wordlist.10000"

response = requests.get(word_site)
WORDS = response.content.splitlines()

Alternatively, you can use the built in urllib2.

import urllib2

word_site = "https://www.mit.edu/~ecprice/wordlist.10000"

response = urllib2.urlopen(word_site)
txt = response.read()
WORDS = txt.splitlines()
2 of 8
20

Solution for Python 3

For Python3 the following code grabs the word list from the web and returns a list. Answer based on accepted answer above by Kyle Kelley.

import urllib.request

word_url = "http://svnweb.freebsd.org/csrg/share/dict/words?view=co&content-type=text/plain"
response = urllib.request.urlopen(word_url)
long_txt = response.read().decode()
words = long_txt.splitlines()

Output:

>>> words
['a', 'AAA', 'AAAS', 'aardvark', 'Aarhus', 'Aaron', 'ABA', 'Ababa',
 'aback', 'abacus', 'abalone', 'abandon', 'abase', 'abash', 'abate',
 'abbas', 'abbe', 'abbey', 'abbot', 'Abbott', 'abbreviate', ... ]

And to generate (because it was my objective) a list of 1) upper case only words, 2) only "name like" words, and 3) a sort-of-realistic-but-fun sounding random name:

import random
upper_words = [word for word in words if word[0].isupper()]
name_words  = [word for word in upper_words if not word.isupper()]
rand_name   = ' '.join([name_words[random.randint(0, len(name_words))] for i in range(2)])

And some random names:

>>> for n in range(10):
        ' '.join([name_words[random.randint(0,len(name_words))] for i in range(2)])

    'Semiramis Sicilian'
    'Julius Genevieve'
    'Rwanda Cohn'
    'Quito Sutherland'
    'Eocene Wheller'
    'Olav Jove'
    'Weldon Pappas'
    'Vienna Leyden'
    'Io Dave'
    'Schwartz Stromberg'
Top answer
1 of 1
5
import itertools
from multiprocessing import Process, Manager

dictionary_file = '/usr/share/dict/words'
letter_list = ['t','b','a','n','e','a','c','r','o']
control_letter = 'e'

By convention, global constant should be named in ALL_CAPS

manager = Manager()
word_list = manager.list()

def new_combination(i, dictionary):
    comb_list = itertools.permutations(letter_list,i)
    for item in comb_list:
        item = ''.join(item)
        if(item in dictionary):

You don't need the parens. Also, dictionary in your code is a list. Checking whether an item is in a list is rather slow, use a set for fast checking.

            word_list.append(item)

Having a bunch of different processes constantly adding onto a single list, performance will be decreased. You are probably better off adding onto a seperate list and then using extend to combine them at the end.

    return

There is no point in an empty return at the end of a function

def make_dictionary():

I'd call this read_dictionary, since you aren't really making the dictionary

    my_list = []

Name variables for what they are for, not their types

    dicts = open(dictionary_file).readlines()
    for word in dicts:

Actually, you could just do for word in open(dictionary_file) for the same effect

        if control_letter in word:
            if(len(word) >3 and len(word)<10):
                word = word.strip('\n')

I recommend stripping before checking lengths, just to make it easier to follow what's going on

                my_list.append(word)
    return my_list

def main():
    dictionary = make_dictionary()
    all_processes = []
    for j in range(9,10):
        new_combo = Process(target = new_combination, args = (j,dictionary,))

You don't need that last comma

        new_combo.start()
        all_processes.append(new_combo)
    while(all_processes):

Parens unneeded

        for proc in all_processes:
            if not proc.is_alive():
                proc.join()
        all_processes = [proc for proc in all_processes if proc.is_alive()]

What happens if a process finishes between the last two lines? You'll never call proc.join() on it.

        if(len(all_processes) == 0):
            all_processes = None

an empty list is already considered false, so there is no point in this.

Actually, there is no reason for most of this loop. All you need is

for process in all_processes:
    process.join()

It'll take care of waiting for all the processes to finish. It'll also be faster since it won't busy loop.

    print list(set(word_list))

if __name__ == '__main__':
    main()

I've given a few suggestions for speed along the way. But what you should really do is invert the problem. Don't look at every combination of letters to see if its a word. Look at each word in the dictionary and see if you can form it out of your letters. That should be faster because there are many fewer words in the dictionary then possible combination of letters.

Top answer
1 of 3
6

This isn't Python specific, but in tails, every letter will map to at least all the vowels. Since every entry contains the vowels aeiou, I'd probably make that implicit for the sake of brevity, maintainability, and space. You could automatically append the voewels to the result of the lookup, then only store in the dictionary the unique letters ("bjlry" for the case of "b" for example). You'd have to figure out how to handle letters like "a" that map to everything though, but that might be made easier with my next suggestions.


LETTERS is unnecessary. Python already has this in the string module:

from string import ascii_lowercase

You could use that with sets to generate consonants:

LETTERS = set(ascii_lowercase)
VOWELS = set("aeiou")
CONSONANTS = LETTERS - VOWELS

Then you could change your tails to something like:

unique_tails = {
    'a': CONSONANTS,
    'b': 'bjlry',
    'c': 'chjklry',
    'd': 'dgjwy',
    'e': CONSONANTS,
    . . .

And then change your loops to something like:

if r in tails[h] or r in VOWELS:

You may find this ends up nicer. I like to avoid duplication, so I'd go in this direction, but you may find it complicates matters.


You use a lot of single-letter variable names, and it's hurting readability. i for an index is common and fine, but h, w, and r should really be spelled out so their purpose is clearer.


random.randint(0, 9999) % 2 == 0 seems convoluted. As far as I can tell, that's just basically a "coin-flip", but it's basing it on a random number from 0-9999 for some reason. I think the 9999 is a red-herring that makes the code harder to understand,and it would be clearer to just generate a single random bit:

if random.getrandbits(1) == 0:  # Or maybe just if random.getrandbits(1):
2 of 3
3

Since you've requested input on how to improve the algorithm in addition to directly improving code (and I know very little about Python anyways), I'll share my idea on it.

Use Markov chains

It's pretty close to what you're already doing, but determines the following letter based on many letters before it, not just one. Obviously, it will have vastly bigger lookup table, so you'll also want to write a (probably separate) program that parses dictionary and stores that data for word generation. It's up to you how to store result, one of viable options is to use sqlite due to relative ease of use, great speed and ability to operate in-memory. My testing reveals that optimal amount of letters to account for is 3: less gives incoherent results and more leads to words being too close to existing ones.

Also, Markov chains aren't limited to word generation. With some tweaking it should be possible to produce (rather odd) texts.

🌐
YouTube
youtube.com › codeflare
python word generator from letters - YouTube
Download this code from https://codegive.com Title: Building a Python Word Generator from LettersIntroduction:In this tutorial, we will explore how to create...
Published   December 11, 2023
Views   6
Find elsewhere
🌐
GitHub
github.com › greghaskins › gibberish
GitHub - greghaskins/gibberish: Python pseudo-word generator
>>> from gibberish import Gibberish >>> gib = Gibberish() >>> gib.generate_word() 'zept' >>> gib.generate_word(start_vowel=True) 'ientz' >>> gib.generate_word(end_vowel=True) 'twae' >>> gib.generate_words(3) ['sqiounn', 'nuil', 'hydrieucks'] It also works as a console script: ~$ gibberish 6 strit druf doct vel dosk flomp ~$ gibberish brank ~$ gibberish 1 -l large fabaduk ~$ gibberish 2 -l medium voskot koontan · To install the gibberish module and console script globally, clone this repository and run: ~$ python setup.py install · (2017.5.11) Analyze the components from CMUdict (nltk.corpus.cmudict) entries.
Starred by 85 users
Forked by 17 users
Languages   Python 100.0% | Python 100.0%
🌐
vimtutor
remarkablemark.org › blog › 2021 › 12 › 05 › python-generate-random-word-or-letter
Python generate a random word or letter | remarkablemark
December 5, 2021 - This post goes over how to generate a random word or letter in Python. Install random-word and PyYaml: pip3 install random-word pyyaml · PyYaml is required or else you’ll get the error: ModuleNotFoundError: No module named 'yaml' Generate a random word: from random_word import RandomWords random_words = RandomWords() print(random_words.get_random_word()) See the package documentation for more information.
🌐
GitHub
github.com › ggouzi › markov-word-generator
GitHub - ggouzi/markov-word-generator: A small Python library to generate random credible words based on a list of words by estimating the probability of the next character from the frequency of the previous ones · GitHub
Markov-Word-Generator is a Python library for generating random, credible, and plausible words based on a list of words. It estimates the probability of the next character in a word based on the frequency of the previous N characters, using ...
Starred by 8 users
Forked by 3 users
Languages   Python
🌐
PyPI
pypi.org › project › Random-Word-Generator
Random-Word-Generator · PyPI
July 26, 2020 - Only Python version >= 3 is required · It helps us to generate random words i.e random noise in text data which is helpful in many text augmentation based tasks, NER, etc. from RandomWordGenerator import RandomWord # Creating a random word object rw = RandomWord(max_word_size, constant_word_size=True, include_digits=False, special_chars=r"@_!#$%^&*()<>?/\|}{~:", include_special_chars=False) Simple random word generation with constant word size ·
      » pip install Random-Word-Generator
    
Published   Feb 15, 2021
Version   1.3
🌐
GitHub
github.com › jweinst1 › Random-Word-Generator
GitHub - jweinst1/Random-Word-Generator: A python program that generates random words of a specific length and starting letter. Uses an algorithm that only makes words based on English grammar rules. Useful for coming up with new names for businesses or apps.
A python program that generates random words of a specific length and starting letter. Uses an algorithm that only makes words based on English grammar rules. Useful for coming up with new names for businesses or apps.
Starred by 7 users
Forked by 6 users
Languages   HTML 58.2% | Python 41.8% | HTML 58.2% | Python 41.8%
🌐
PyPI
pypi.org › project › Random-Word
Random-Word
January 31, 2021 - JavaScript is disabled in your browser · Please enable JavaScript to proceed · A required part of this site couldn’t load. This may be due to a browser extension, network issues, or browser settings. Please check your connection, disable any ad blockers, or try using a different browser
🌐
DEV Community
dev.to › lubiah › generating-random-words-in-python-2obi
Generating random words in python - DEV Community
September 10, 2021 - It contains a collection of string constants import random #Python's module for generating random objects lowercase_letters = string.ascii_lowercase #A constant containing lowercase letters def lowercase_word(): #The function responsible for generating the word lowercase word = '' #The variable which will hold the random word random_word_length = random.randint(1,10) #The random length of the word while len(word) != random_word_length: #While loop word += random.choice(lowercase_letters) #Selects a random character on each iteration return word #Returns the word random_word = lowercase_word()
🌐
Quora
quora.com › How-do-you-generate-a-random-word-from-a-list-in-Python
How to generate a random word from a list in Python - Quora
Answer (1 of 3): There is something called choice function in the random module of Python. You can use it the following way. [code]import random word_list = ['apple','banana','cherry','dates','etc'] random.choice(word_list) [/code]This gives you a random word from a list in Python. Also, in Py...
🌐
GeeksforGeeks
geeksforgeeks.org › python › possible-words-using-given-characters-python
Possible Words using given characters in Python - GeeksforGeeks
November 12, 2025 - chars.copy() and remove(c): prevent reuse of the same letter. fun(n1, word + c): continues forming longer words recursively. Test for Word construction from character list · Words extraction from set of characters using dictionary · Create Quiz · Comment · S · Shashank Mishra · Follow · 6 · Improve · S · Shashank Mishra · Follow · 6 · Improve · Article Tags : Python ·
Top answer
1 of 2
2

Algorithm

The problem here is that your algorithm isn't scalable. For any given n-letter word, prob_words() generates n! candidate words. That's 40320 candidates for an 8-letter input.

To compound your performance problem, check_word() opens and scans the word list file once for each candidate word. Since the entire word list should fit quite comfortably memory on any general-purpose computer these days, you should read the word list just once.

So, forget about multithreading or multiprocessing. Work smarter, not harder! If you want to determine whether two words are anagrams of each other, all you need is to count or sort the letters. You don't need to generate a combinatoric explosion.

Design

GetReadableWords is not a well designed class. A good hint that the design is wrong is that classses (and objects) should be named like a noun, not a verb phrase. A second hint that you've gone wrong is that letters is really an input for just prob_words(), and not so much for chek_words().

In addition, neither prob_words() nor chek_words() is a good method name. Those names make no sense to me.

There is way too much code under if __name__ == "__main__". If you have that much code, then you should put it in a main() function and call it.

Suggested solution

'''Generate English words from given letters'''

class AnagramWordFinder:
    def __init__(self, word_list_filename='corncob_lowercase.txt'):
        self.vocab = {}
        with open(word_list_filename) as f:
            for line in f:
                word = line.rstrip()
                self.vocab.setdefault(''.join(sorted(word)), []).append(word)

    def words_from_letters(self, letters):
        return self.vocab.get(''.join(sorted(letters)), [])

def main():
    word_finder = AnagramWordFinder()
    print(word_finder.words_from_letters(input('Enter your characters: ')))

if __name__ == '__main__':
    main()

Arguably, you don't even need a class, especially if you only need to ask for input only once.

def unscramble_letters(letters, word_list_filename='corncob_lowercase.txt'):
    letters = ''.join(sorted(letters))
    with open(word_list_filename) as f:
        for line in f:
            if ''.join(sorted(line.rstrip())) == letters:
                yield line.rstrip()

if __name__ == '__main__':
    print(list(unscramble_letters(input('Enter your characters: '))))
2 of 2
1

Anagram lookup:

Unless capitalization is important, fold everything to, say, lowercase.

  1. Prep the list of valid rows by building a hash (associative array) mapping sorted letters to the word.
  2. When you have a set of letters, sort those letters, too.
  3. Then do a hashed lookup of step 2 in the array of step 1.

Step 1 might produce, for example:

amp => amp
amp => map
oot => too
🌐
Reddit
reddit.com › r/python › created a random word generator program, looking for criticism
r/Python on Reddit: Created a random word generator program, looking for criticism
August 24, 2015 -

Hi, r/python, I'm new to programming, and made a python program that generates semi-pronounce-able words:

import random import math import time

CONSONANTS = [chr(i+97) for i in range(26)] + ["", ""]
# ^ I put those last two spaces in the consonants list so that                                      the program can generate
#words with consecutive vowels

VOWELS = ["a", "e", "i", "o", "u"]

def randVowel():
    letter = random.choice(VOWELS)
    return letter

def randCons():
    consonant = random.choice(CONSONANTS)
    return consonant

def randWord():
    word = []
    randRange = random.randint(3,4)
    for i in range(randRange):
        letter = randVowel()
        word += letter
        letter = randCons()
        word += letter
    word = "".join(str(x) for x in word) #to convert the list to a      string
    return word #returns a random word

while True:
    print("\nHere's a random word: ")
    print(randWord())
    time.sleep(1)
Top answer
1 of 4
4
Read the sidebar for how to post your code. Alternatively, upload to http://codepad.org/?lang=Python I'm not going to critique your actual code until it is more readable, but as for your algorithm, I think you would do better to include dipthongs (e.g. ou) as vowels and digraphs (e.g. sh) and blends (e.g. pt) as consonants. I recommend this because words aren't really strings of letters, but strings of syllables, which can be more closely estimated than simply in terms of vowels and consonants. As an example, just alternating consonants and vowels will always produce words like Pokawy or Renika, which tend to have a very distinctive and somewhat artificial sound (although words generated this way can be very similar to those of the native Hawaiian language), while including dipthongs, blends, and digraphs can produce words more along the lines of eptia or temmish. That being said, this still isn't a great system. Of course, depending on what real-life language you are trying to emulate (if any) your system is going to have to be different. But even assuming you're trying to make English-sounding words, improvements can certainly be made. For example, the frequency of certain sounds coming after others more closely matches those from a dictionary. But those innovations are up to you to implement, should you desire. You could even look into having suffix and prefix generators, really the possibilities are endless. This might be useful: http://school.judsonisd.org/webpages/cbianco/readinghelp.cfm?subpage=23376
2 of 4
3
This should probably be in r/learnpython . But since I'm bored on a plane I feel compelled to answer! How about something like this import random from string import ascii_lowercase VOWELS = ['a', 'e', 'i', 'o', 'u'] CONSONANTS = [ c for c in ascii_lowercase if c not in VOWELS] + ['']*2 def random_word(): """ Returns a random word composed of consonants and vowels """ word = '' random_range = random.randint(3,4) for i in range(random_range): word += random.choice(VOWELS) + random.choice(CONSONANTS) return word I hope the above acts as constructive criticism.
🌐
Word Raiders
wordraiders.com › solvers › word-generator-from-letters
Word Generator From Letters - Word Raiders
How to use the Word Generator From Letters? There's no better place to quickly generate a list of all words you can create from your letters. You can do this in two ways, depending on your situation: Unscramble words from letters: place your letters in the unscramble box and generate all the ...