##open file and create a dictionary of {"word":"sorted word"}
word_file = open("word_list(1).txt","r")
word_list = {}
for text in word_file:
simple_text = ''.join(sorted(text.lower().strip()))
word_list.update({text.lower().strip():simple_text})
##lowercase and sort the user input word
def simplify_entered_word():
lower_word = ''.join(sorted(input_word.lower().strip())) #Creates a list with the lowercase, sorted letters.
return lower_word
#Compare the sorted user input with the values of the dictionary to find the anagrams.
def find_in_dict(entered_word):
for key,val in word_list.items():
if val == entered_word:
print(key,input_word)
##main loop
while True:
input_word = input("Input the word for anagram checking: ")
find_in_dict(simplify_entered_word())
1 Answer
Good that you tagged with Python 3, as it kinda works in Python 2.7 with a bit different behaviour.
All the time reminder to format according to
PEP8; here I'd note that
there should be spaces between names, i.e. key, val
and
print(key, input_word)
.
Firstly, it's good that there are functions to split the logic up. However part of that is negated by using globals. In general using globals is a bad pattern - here in particular it makes more sense to pass the word list through to the individual functions.
Edit: And I forgot to update it to not use globals, shame on me ...
Most of the comments can also be docstrings instead.
Now, for the globals. Just pass them through to the functions:
def simplify_entered_word(input_word):
"Lowercase and sort the user input word."
word = input_word.lower().strip()
return word, "".join(sorted(word))
This function can now also be reused easily by returning two results, the lowercased word and the sorted result.
Next I'd move the word list reading its own function:
def read_word_list(filename):
"""Open file and create a dictionary of {"word":"sorted word"}."""
with open(filename, "r") as word_file:
word_list = {}
for text in word_file:
word = text.lower().strip()
simple_text = "".join(sorted(word))
word_list.update({word: simple_text})
return word_list
However this can also be much easier in terms of simplify_entered_word
:
def read_word_list(filename):
"""Open file and create a dictionary of {"word":"sorted word"}."""
with open(filename, "r") as word_file:
return {simple[0]: simple[1]
for simple in map(simplify_entered_word, word_file)}
N.b. there might be a better way to write that dictionary
comprehension. Note also that I used with
as to not leak the file
handle from open
.
And then call that with the filename:
if __name__ == "__main__":
word_list = read_word_list("word_list(1).txt")
while True:
input_word = input("Input the word for anagram checking: ")
find_in_dict(word_list, simplify_entered_word(input_word)[1])
Just in case this will only run as a script and not if the file is imported somewhere else, which is good practice.
One problem that still remains is the iteration in find_in_dict
. It'd
be much simpler if the data structure is slightly changed by collecting
all words for one anagram into a list:
from collections import defaultdict
def read_word_list(filename):
"""Open file and create a dictionary of {"word":"sorted word"}."""
with open(filename, "r") as word_file:
word_list = defaultdict(list)
for word, simplified in map(simplify_entered_word, word_file):
word_list[simplified].append(word)
return word_list
def find_in_dict(word_list, entered_word):
"""Compare the sorted user input with the values of the dictionary to find
the anagrams."""
for name in word_list.get(entered_word, []):
print(name, entered_word)
Note the use of defaultdict
to simplify the automatic creation of the
list.
-
1\$\begingroup\$ "N.b. there might be a better way to write that dictionary comprehension." It's not using a comprehension at all, ;P
dict(map(simplify_entered_word, word_file))
. You change how you use thedict
with thedefaultdict
addition, if you didn't you could usedefaultdict(int, map(lambda x: (x, x*2), range(10)))
. \$\endgroup\$– Peilonrayz ♦Commented Apr 8, 2016 at 7:58