import itertools from collections import Counter from dictionary import Dictionary, DICTS def make_letter_key(letters): return frozenset(Counter(letters).items()) def make_key(dictionary_name, letters): return (dictionary_name, make_letter_key(letters)) def candidates(letters, dictionary: Dictionary, min=2, permutations=None): if permutations is None: permutations = tuple( map( "".join, itertools.chain.from_iterable( map( lambda r: itertools.permutations(letters, r), range(min, len(letters) + 1), ) ), ) ) return dictionary.filter(permutations), permutations class CandidateCache: def __init__(self, maxsize=5): self.maxsize = maxsize self.cache = {} self.permutations_cache = {} self.permutations_keys = [] self.keys = [] def get(self, dictionary_name, letters): key = make_key(dictionary_name, letters) try: return self.cache[key] except KeyError: try: permutations = self.get_permutation(letters) add = False except KeyError: permutations = None add = True data, permutations = candidates( letters, DICTS[dictionary_name], permutations=permutations ) if add: self.append_permutation(letters, permutations) self.create(key, data) return data def get_permutation(self, letters): key = make_letter_key(letters) return self.permutations_cache[key] def create(self, key, data): if len(self.keys) > self.maxsize: key = self.keys.pop() del self.cache[key] self.keys.insert(0, key) self.cache[key] = data def append_permutation(self, letters, permutations): if len(self.permutations_keys) > self.maxsize: dkey = self.permutations_keys.pop() del self.permutations_cache[dkey] key = make_letter_key(letters) self.permutations_cache[key] = permutation