from collections import defaultdict
import re

from nltk.corpus import cmudict


d = cmudict.dict()


def get_rhymes_dict():
    rhymes = defaultdict(list)
    for (word, prons) in d.iteritems():
        for pron in prons:
            rhymes[tuple(pron[1:])].append(word)
    return rhymes


def words_starting_with(letter):
    for word in d.iterkeys():
        if word.startswith(letter):
            yield word


def get_first_letter_variants(letters):
    rhymes_dict = get_rhymes_dict()
    pairs = []
    needs_letters = set(letters)
    pattern = re.compile("^[%s]" % ''.join(letters))
    seen_words = set()
    for word in words_starting_with(letters[0]):
        for pronunciation in d[word]:
            has_letters = set()
            rhymes = rhymes_dict[tuple(pronunciation[1:])]
            if len(rhymes) < len(letters):
                break
            # Filter out words that don't start with the desired letters
            filtered_rhymes = []
            for word in rhymes:
                if pattern.match(word) and word not in seen_words:
                    has_letters.add(word[0])
                    filtered_rhymes.append(word)
                    seen_words.add(word)
            if has_letters == needs_letters:
                pairs.append(filtered_rhymes)
    return pairs

@@ -126,106 +126,312 @@
     
-rhymes = defaultdict(list)%0A    for (word, prons) in d.iteritems():%0A        for pron in prons:%0A    
+%22%22%22Get the cmudict as a rhymes dictionary.%0A%0A    This maps similar phonemes to each other, skipping the first phoneme.%0A    You end up with a dict like%0A%0A        %7B('AU1', 'G', 'Z'): %5B'dogs', 'logs', ...%5D, ...%7D%0A    %22%22%22%0A    rhymes = defaultdict(list)%0A    for (word, pronunciation) in iter(cmudict.entries()):%0A
     
@@ -451,16 +451,25 @@
 ple(pron
+unciation
 %5B1:%5D)%5D.a

Build the rhymes dict in a way that doesn't depend on global dict