Skip to content

Instantly share code, notes, and snippets.

@sjolsen
Created March 14, 2024 06:47
Show Gist options
  • Save sjolsen/72a9e6fed8a3089c7b2d76681cfeb9ee to your computer and use it in GitHub Desktop.
Save sjolsen/72a9e6fed8a3089c7b2d76681cfeb9ee to your computer and use it in GitHub Desktop.
word permutations
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