Welcome to CodeReview! First, congratulations on writing a working Python program that is clean, straightforward, and easy to understand.
Now let's see if we can make it better!
Style
There are two things I think you could improve stylistically. First, your comments are a little too much. I know people encourage you to write comments. But you need to be careful of the kind of comments you write.
Comments should be used to provide extra information. When you have code like this:
# open word files
wordlist = open("wordlist.txt", "r").read().split()
words = open("words.txt", "r").read().split()
Is the comment really adding value? A comment that states in English what your code states in Python is a wasted comment. You want to explain what you are doing rather than focus on how you do it. And you should only explain things that don't already have a set of names explaining it. If you're calling an open
function, you don't need to explain that you are opening something. If you're storing data into a variable called wordlist
, you probably don't need to explain that you are reading a word list. Use a light touch with your commentary.
Second, it's very much preferred in Python 3 to use the context manager features of file objects. If you are going to read in the entire contents of a file, use a with
block to open, read, and close the file safely.
with open("wordlist.txt", 'r') as wlist:
wordlist = wlist.read().split()
Since you do this twice, you might write a function to do it for you. (You say you're a beginner, so I'm not sure if you've learned functions yet.)
Performance
Looking at the "skeleton" of your code:
for word in words:
for compare in wordlist:
for char in word:
Your performance is going to be \$O(m \times n \times o)\$ where m
is the number of scrambled words, n
is the number of words in the master wordlist, and o
is the average word length.
The phrasing of the problem statements suggests that the scrambled words are a small subset of the inputs. But the worst case is that the scrambled words are the entire wordlist, making your worst-case performance \$O(n^2)\$ which will really hurt for large values of n
.
You can improve this performance by converting \$m \times n\$ into \$m + n\$. Make a pass through one list computing a "signature" for each word. Store the signatures in a Python dict
(dictionary) object mapping the signature to the original word(s) with that signature. Then make a pass through the second list, computing a "signature" for those words that can compare with the first signature. Check each word in the second list to see if its signature is in the dictionary, and store the results if so.
This process, if you can find the right signature, will work for a large number of problems.
You want a signature that does not depend on the ordering of the letters, since by definition one set of letters is scrambled. One easy mechanism would be to sort the letters into ASCII order, so that "banana" -> "aaabnn" for example.
Your code would then look like this:
signatures = dict()
for word in wordlist:
sig = ''.join(sorted(word))
signatures[sig] = word
found_words = []
for dwro in scrambled_words:
sig = ''.join(sorted(dwro))
if sig in signatures:
found_words.append(signatures[sig])
Note: There's a potential issue, in that words like "keep" and "peek" are going to have the same signature, since they have all the same letters. You will have to decide how to handle that, but if you decide to maintain a list of all possible words for a signature, you should look at collections.defaultdict
.