Created
March 14, 2024 06:47
-
-
Save sjolsen/72a9e6fed8a3089c7b2d76681cfeb9ee to your computer and use it in GitHub Desktop.
word permutations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import collections | |
import dataclasses | |
import sys | |
from typing import Iterable, Self | |
IGNORED_WORDS: frozenset[str] = frozenset([ | |
'adv', | |
'dis', | |
'eds', | |
'gad', | |
'med', | |
]) | |
# mega, mage | |
@dataclasses.dataclass(frozen=True) | |
class Components: | |
counts: tuple[tuple[str, int], ...] | |
@classmethod | |
def from_str(cls, s: str) -> Self: | |
counts: dict[str, int] = collections.defaultdict(int) | |
for c in s: | |
counts[c] += 1 | |
return cls(tuple(sorted(counts.items()))) | |
def __le__(self, other: 'Components') -> bool: | |
i = iter(other.counts) | |
for l, lcount in self.counts: | |
for r, rcount in i: | |
if l == r: | |
break | |
else: | |
return False | |
if lcount > rcount: | |
return False | |
return True | |
Dictionary = dict[Components, set[str]] | |
def load_dictionary(path: str) -> Dictionary: | |
dictionary: dict[Components, set[str]] = collections.defaultdict(set) | |
with open(path, 'rt') as f: | |
for line in f: | |
word = line.strip() | |
if len(word) >= 3 and word not in IGNORED_WORDS: | |
dictionary[Components.from_str(word)].add(word) | |
return dictionary | |
def find_words(dictionary: Dictionary, available: Components) -> Iterable[str]: | |
for components, words in dictionary.items(): | |
if components <= available: | |
yield from words | |
def print_words(dictionary: Dictionary, available: Components): | |
for word in sorted(find_words(dictionary, available)): | |
print(word) | |
def main(argv): | |
dictionary = load_dictionary('/usr/share/dict/words') | |
if len(argv) > 1: | |
available = Components.from_str(''.join(argv[1:])) | |
print_words(dictionary, available) | |
else: | |
while True: | |
try: | |
word = input('> ') | |
except EOFError: | |
return | |
available = Components.from_str(word.strip()) | |
print_words(dictionary, available) | |
if __name__ == '__main__': | |
main(sys.argv) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment