From 94557c6bf416dd981d346b19fcb2c0ffbb739585 Mon Sep 17 00:00:00 2001 From: Raphael Roberts Date: Sun, 26 May 2019 01:43:55 -0500 Subject: [PATCH] Made candidate cache and using itertools.permutations --- candidate_cache.py | 36 ++++++++++++++++++++++++++++++++++++ dictionary.py | 1 + main.py | 36 +++++++----------------------------- 3 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 candidate_cache.py diff --git a/candidate_cache.py b/candidate_cache.py new file mode 100644 index 0000000..670f2e9 --- /dev/null +++ b/candidate_cache.py @@ -0,0 +1,36 @@ +import itertools +from dictionary import Dictionary, DICTS + + +def make_key(dictionary_name, letters): + return (dictionary_name, frozenset(letters)) + + +def candidates(letters, dictionary: Dictionary, min=2): + permutations = itertools.chain.from_iterable( + map(lambda r: itertools.permutations(letters, r), range(min, len(letters) + 1)) + ) + return dictionary.filter(map("".join, permutations)) + + +class CandidateCache: + def __init__(self, maxsize=5): + self.maxsize = maxsize + self.cache = {} + self.keys = [] + + def get(self, dictionary_name, letters): + key = make_key(dictionary_name, letters) + try: + return self.cache[key] + except KeyError: + data = candidates(letters, DICTS[dictionary_name]) + self.create(key, data) + return data + + 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 diff --git a/dictionary.py b/dictionary.py index 6243a68..99973ac 100644 --- a/dictionary.py +++ b/dictionary.py @@ -54,3 +54,4 @@ class Dictionary: DEFAULT = Dictionary(default_load_future) ALTERNATE = Dictionary(alternate_load_future) +DICTS = {"default": DEFAULT, "alt": ALTERNATE} diff --git a/main.py b/main.py index 8ad3e22..517ed74 100755 --- a/main.py +++ b/main.py @@ -1,19 +1,18 @@ #!/usr/bin/python3 from string import ascii_lowercase import argparse -import itertools import os import re import cmd2 - -from dictionary import DEFAULT, ALTERNATE +from candidate_cache import CandidateCache +from dictionary import DICTS from word_remove_dialog import RemoveWordsActivity LOWERCASE = set(ascii_lowercase) -DICTS = {"default": DEFAULT, "alt": ALTERNATE} + # argparsers dictionary_manage_parser = argparse.ArgumentParser() commands = dictionary_manage_parser.add_mutually_exclusive_group(required=True) @@ -47,16 +46,6 @@ commands.add_argument( ) -def candidates(letters, min=2): - possibilities = [] - for length in range(min, len(letters) + 1): - for comb in itertools.combinations(letters, length): - for perm in itertools.permutations(comb): - word = "".join(perm) - possibilities.append(word) - return possibilities - - class MainLoop(cmd2.Cmd): """Loop for wordscape commands @@ -69,8 +58,7 @@ class MainLoop(cmd2.Cmd): self.excludes = set() self.hidden = set() self.init_letters(input("Enter letters: ")) - self._candidates = None - self._in_dictionary = None + self.cache = CandidateCache() super().__init__() def init_letters(self, letters): @@ -79,24 +67,14 @@ class MainLoop(cmd2.Cmd): letters = letters.lower() self.letters = [l for l in letters if l in LOWERCASE] self.prompt = MainLoop.prompt.format(", ".join(self.letters)) - self._candidates = None - self._in_dictionary = None @property def candidates(self): - if self._candidates is None: - self._candidates = candidates(self.letters) - return self._candidates - - @property - def in_dictionary(self): - if self._in_dictionary is None: - self._in_dictionary = DICTS[self.dict].filter(self.candidates) - return self._in_dictionary + return self.cache.get(self.dict, self.letters) def filter(self, regex): - matching_pattern = filter(regex.match, self.candidates) - return DICTS[self.dict].filter(matching_pattern) + + return set(filter(regex.match, self.candidates)) @cmd2.with_argparser(dictionary_manage_parser) def do_dict(self, args):