Skip to content

Instantly share code, notes, and snippets.

@kzinglzy
Created June 28, 2014 05:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kzinglzy/5ac5f46ccf6a42582544 to your computer and use it in GitHub Desktop.
Save kzinglzy/5ac5f46ccf6a42582544 to your computer and use it in GitHub Desktop.
Find anagram from dictionary with Python's coroutine
from collections import defaultdict
def find_anagram(input_data):
""" find all the anagram from a dictionary
Anagram: contruct by the same word but have a different order
e.g. 'abc' 'acb' 'bca' is anagram
this solution comes from <Programming Pearls> chapter 2:
pans anps pans anps pans
pots opst pots anps snap pans snap
opt =>sign=> opt opt =>sort=> opt opt =>squash=> opt
snap anps snap opst pots pots stop tops
stop opst stop opst stop
tops opst tops opst tops
Here we use Python's coroutine to simulate Unix's pile
"""
# initize a cotoutine
def coroutine(func):
def start(*args, **kwargs):
g = func(*args, **kwargs)
g.send(None) # init. equal to g.__next__() or next(g)
return g
return start
@coroutine
def sign(target):
""" sign each word by sorted them
e.g.
pans => <sign> => anps
stop => <sign> => opst
opt => <sign> => opt
"""
while True:
words = yield
for w in words:
target.send([''.join(sorted(w)), w]) # [sign_word, original_word]
target.send("DONE") # flag incicates that all data have been seen
@coroutine
def sort(target):
""" sort a words list by their sign """
sign_words = [] # TODO: try to remove this temporary variable
while True:
word = yield
if word == 'DONE':
target.send(sorted(sign_words))
else:
sign_words.append(word)
@coroutine
def squash():
""" merge the words which have the same sign """
nonlocal dictionary # python3 only: use the variable define in outside
while True:
word_list = yield
for x in word_list:
dictionary[x[0]].add(x[1])
dictionary = defaultdict(set)
sign(sort(squash())).send(input_data) # start searching by send a data to func sign
return filter(lambda x: len(x[1]) > 1, dictionary.items()) # filter the word has no anagram
if __name__ == "__main__":
test_data = ['abc', 'acb', 'bca', 'iterl', 'liter', 'hello', 'subessential',
'suitableness', 'hello']
result = find_anagram(test_data)
for each in result:
print(each[0], ':', each[1])
@kzinglzy
Copy link
Author

output:
eilrt : {'iterl', 'liter'}
abeeilnssstu : {'subessential', 'suitableness'}
abc : {'bca', 'acb', 'abc'}

Note that your output will have a different sort from mine, just because the result is a set

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment