ImpracticalPython_Ch3.pdf

(316 KB) Pobierz
So lv ing A n Ag r A m S
3
An
anagram
is a word formed by rearrang-
ing the letters of another word. For example,
Elvis
yields the eerie trio
evils, lives,
and
veils.
Does this mean Elvis still lives but veils his evil
existence? In the book
Harry Potter and the Chamber of
Secrets,
“I am Lord Voldemort” is an anagram of the
evil wizard’s real name, Tom Marvolo Riddle. “Lord
Earldom Vomit” is also an anagram of Tom Marvolo
Riddle, but author J.K. Rowling had the good sense to
pass on that one.
In this chapter, first you’ll find all the anagrams for a given word
or name. Then, you’ll write a program that lets a user interactively build
an anagram phrase from their own name. Finally, you’ll play computer
wizard and see what it takes to extract “I am Lord Voldemort” from
“Tom Marvolo Riddle.”
Project #4: Finding Single-Word Anagrams
You’ll start by analyzing simple single-word anagrams and figuring out how
to identify them programmatically. Having accomplished this, you’ll be
ready to take on anagram phrases in the following section.
The objec Ti v e
Use Python and a dictionary file to find all the single-word anagrams for a given English
word or single name. You can read instructions for finding and loading dictionary files at
the start of Chapter 2.
The Strategy and Pseudocode
More than 600 newspapers and 100 internet sites carry an anagram game
called
Jumble.
Created in 1954, it’s now the most recognized word-scramble
game in the world.
Jumble
can be really frustrating, but finding anagrams
is almost as easy as finding palindromes—you just need to know the com-
mon characteristic of all anagrams: they must have the same number of the
same letters.
Identifying an Anagram
Python doesn’t contain a built-in anagram operator, but you can easily
write one. For the projects in this chapter, you’ll load the dictionary file
from Chapter 2 as a list of strings. So the program needs to verify that
two strings are anagrams of each other.
Let’s look at an example.
Pots
is an anagram of
stop,
and you can verify
that
stop
and
pots
have the same number of letters with the
len()
function.
But there’s no way for Python to know whether two strings have the same
number of any single character—at least not without converting the strings
to another data structure or using a counting function. So, instead of look-
ing at these two words simply as strings, you can represent them as two lists
containing single-character strings. Create these lists in a shell, like IDLE,
and name them
word
and
anagram
, as I’ve done here:
>>>
word = list('stop')
>>>
word
['s', 't', 'o', 'p']
>>>
anagram = list('pots')
>>>
anagram
['p', 'o', 't', 's']
These two lists match our description of an anagram pair; that is, they
contain the same number of the same letters. But if you try to equate them
with the comparison operator
==
, the result is
False
.
36
Chapter 3
>>>
anagram == word
False
The problem is that the operator (
==
) considers two lists equivalent
only if they have the same number of the same list items and those items
occur in the same order. You can easily solve this problem with the built-
in function
sorted()
, which can take a list as an argument and reorder its
contents alphabetically. So, if you call
sorted()
twice—once for each of the
lists—and then compare the sorted lists, they will be equivalent. In other
words,
==
returns
True
.
>>>
word = sorted(word)
>>>
word
['o', 'p', 's', 't']
>>>
anagram = sorted(anagram)
>>>
anagram
['o', 'p', 's', 't']
>>>
anagram == word
True
You can also pass a string to
sorted()
to create a sorted list like the ones
in the preceding code snippet. This will be useful for converting the words
from the dictionary file into sorted lists of single-character strings.
Now that you know how to verify that you’ve found an anagram, let’s
design the script in its entirety—from loading a dictionary and prompt-
ing the user for a word (or name) to searching for and printing all the
anagrams.
Using Pseudocode
Remember that planning with pseudocode will help you spot potential
issues and spotting those issues early will save you time. The following
pseudocode should help you better understand the script we’ll write in the
next section,
anagrams.py.
Load digital dictionary file as a list of words
Accept a word from user
Create an empty list to hold anagrams
Sort the user-word
Loop through each word in the word list:
Sort the word
if word sorted is equal to user-word sorted:
Append word to anagrams list
Print anagrams list
The script will start by loading words from a dictionary file into a list as
strings. Before you loop through the dictionary in search of anagrams, you
need to know which word you want anagrams of, and you need a place to
store anagrams when you find them. So, first ask the user to input a word
Solving Anagrams
37
and then create an empty list to store the anagrams. Once the program
has looped through every word in the dictionary, it will print that list of
anagrams.
Anagram-Finder Code
Listing 3-1 loads a dictionary file, accepts a word or name
specified within
the program,
and finds all the anagrams in the dictionary file for that word
or name. You’ll also need the dictionary-loading code from Chapter 2.
You can download these from
https://www.nostarch.com/impracticalpython/
as
anagrams.py
and
load_dictionary.py,
respectively. Keep both files in the
same folder. You can use the same dictionary file you used in Chapter 2
or download another one (see Table 2-1 on page 20 for suggestions).
anagrams.py
import load_dictionary
word_list = load_dictionary.load('2of4brif.txt')
anagram_list = []
# input a SINGLE word or SINGLE name below to find its anagram(s):
name = 'Foster'
print("Input name = {}".format (name))
name = name.lower()
print("Using name = {}".format(name))
# sort name & find anagrams
name_sorted = sorted(name)
for word in word_list:
word = word.lower()
if word != name:
if sorted(word) == name_sorted:
anagram_list.append(word)
# print out list of anagrams
print()
if len(anagram_list) == 0:
print("You need a larger dictionary or a new name!")
else:
�½
print("Anagrams =", *anagram_list, sep='\n')
Listing 3-1: Given a word (or name) and a dictionary file, this program searches for and
prints a list of anagrams.
You start by importing the
load_dictionary
module you created in
Chapter 2
.
This module will open a dictionary text file and, with its
load()
function, load all the words into a list
.
The
*.txt
file you use may
be different, depending on which dictionary file you downloaded (see
“Finding and Opening a Dictionary” on page 20).
Next, create an empty list, called
anagram_list
, to hold any anagrams
you find
.
Have the user add a
single
word, such as their first name
.
This
38
Chapter 3
doesn’t have to be a proper name, but we’ll refer to it as
name
in the code
to distinguish it from a dictionary
word
. Print this name so the user can see
what was entered.
The next line anticipates a problematic user action. People tend to
type their name with an uppercase first letter, but dictionary files may not
include uppercase letters, and that matters to Python. So, first convert all
letters to lowercase with the
.lower()
string method
.
Now sort the name
.
As mentioned previously, you can pass
sorted()
a
string as well as a list.
With the input sorted alphabetically in a list, it’s time to find anagrams.
Start a loop through each word in the dictionary word list
.
To be safe, con-
vert the word to lowercase, as comparison operations are case-sensitive. After
the conversion, compare the word to the unsorted name, because a word
can’t be an anagram of itself. Next, sort the dictionary word and compare it
to the sorted name. If it passes, append that dictionary word to
anagram_list
.
Now display the results. First, check whether the anagram list is empty.
If it is, print a whimsical reply so you don’t just leave the user hanging
.
If
the program found at least one anagram, print the list using the splat (
*
)
operator. Remember from Chapter 2 that splat lets you print each member
of a list on a separate line
�½.
The following is example output for this program, using the input
name
Foster:
Input name = Foster
Using name = foster
Anagrams =
forest
fortes
softer
If you’d like to use another input, change the value of the
name
variable
in the source code. As an exercise, try to adjust the code so that the user
is prompted to input the name (or word); you can do this with the
input()
function.
Project #5: Finding Phrase Anagrams
In the previous project, you took a single name or word and rearranged all
the letters to find single-word anagrams. Now you will derive multiple words
from a name. The words in these
phrase anagrams
form only part of the input
name, and you will need several words to exhaust the available letters.
The objec Ti v e
Write a Python program that lets a user interactively build an anagram phrase from the
letters in their name.
Solving Anagrams
39
Zgłoś jeśli naruszono regulamin