Archive:Think Python/Tuples
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML> <HEAD>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <META name="GENERATOR" content="hevea 1.10"> <LINK rel="stylesheet" type="text/css" href="book.css"> <TITLE>Tuples</TITLE> </HEAD> <BODY > <A HREF="book012.html"><IMG SRC="previous_motif.gif" ALT="Previous"></A> <A HREF="index.html"><IMG SRC="contents_motif.gif" ALT="Up"></A> <A HREF="book014.html"><IMG SRC="next_motif.gif" ALT="Next"></A>
<A NAME="htoc143">Chapter 12</A> Tuples
<A NAME="tuplechap"></A>
<A NAME="toc130"></A><A NAME="htoc144">12.1</A> Tuples are immutable
<A NAME="@default1024"></A>
<A NAME="@default1025"></A>
<A NAME="@default1026"></A>
A tuple is a sequence of values. The values can be any type, and
they are indexed by integers, so in that respect tuples are a lot
like lists. The important difference is that tuples are immutable.
<A NAME="@default1027"></A> <A NAME="@default1028"></A>
Syntactically, a tuple is a comma-separated list of values:
<FONT COLOR=blue><FONT SIZE=4>>>> t = 'a', 'b', 'c', 'd', 'e' </FONT></FONT>
Although it is not necessary, it is common to enclose tuples in parentheses:
<A NAME="@default1029"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> t = ('a', 'b', 'c', 'd', 'e')
</FONT></FONT>To create a tuple with a single element, you have to include the final comma:
<A NAME="@default1030"></A> <A NAME="@default1031"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> t1 = ('a',)
>>> type(t1)
<type 'tuple'>
</FONT></FONT>Without the comma, Python treats ('a') as a string in
parentheses:
<FONT COLOR=blue><FONT SIZE=4>>>> t2 = ('a')
>>> type(t2)
<type 'str'>
</FONT></FONT>Another way to create a tuple is the built-in function tuple. With no argument, it creates an empty tuple:
<A NAME="@default1032"></A> <A NAME="@default1033"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> t = tuple() >>> print t () </FONT></FONT>
If the argument is a sequence (string, list or tuple), the result is a tuple with the elements of the sequence:
<FONT COLOR=blue><FONT SIZE=4>>>> t = tuple('lupins')
>>> print t
('l', 'u', 'p', 'i', 'n', 's')
</FONT></FONT>Because tuple is the name of a built-in function, you should avoid using it as a variable name.
Most list operators also work on tuples. The bracket operator indexes an element:
<A NAME="@default1034"></A> <A NAME="@default1035"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> t = ('a', 'b', 'c', 'd', 'e')
>>> print t[0]
'a'
</FONT></FONT>And the slice operator selects a range of elements.
<A NAME="@default1036"></A>
<A NAME="@default1037"></A> <A NAME="@default1038"></A>
<A NAME="@default1039"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> print t[1:3]
('b', 'c')
</FONT></FONT>But if you try to modify one of the elements of the tuple, you get an error:
<A NAME="@default1040"></A>
<A NAME="@default1041"></A> <A NAME="@default1042"></A>
<A NAME="@default1043"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> t[0] = 'A' TypeError: object doesn't support item assignment </FONT></FONT>
You can’t modify the elements of a tuple, but you can replace one tuple with another:
<FONT COLOR=blue><FONT SIZE=4>>>> t = ('A',) + t[1:]
>>> print t
('A', 'b', 'c', 'd', 'e')
</FONT></FONT><A NAME="toc131"></A><A NAME="htoc145">12.2</A> Tuple assignment
<A NAME="tuple assignment"></A>
<A NAME="@default1044"></A>
<A NAME="@default1045"></A> <A NAME="@default1046"></A>
<A NAME="@default1047"></A>
It is often useful to swap the values of two variables.
With conventional assignments, you have to use a temporary
variable. For example, to swap a and b:
<FONT COLOR=blue><FONT SIZE=4>>>> temp = a >>> a = b >>> b = temp </FONT></FONT>
This solution is cumbersome; tuple assignment is more elegant:
<FONT COLOR=blue><FONT SIZE=4>>>> a, b = b, a </FONT></FONT>
The left side is a tuple of variables; the right side is a tuple of
expressions. Each value is assigned to its respective variable. All the expressions on the right side are evaluated before any
of the assignments.
The number of variables on the left and the number of values on the right have to be the same:
<A NAME="@default1048"></A> <A NAME="@default1049"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> a, b = 1, 2, 3 ValueError: too many values to unpack </FONT></FONT>
More generally, the right side can be any kind of sequence
(string, list or tuple). For example, to split an email address
into a user name and a domain, you could write:
<A NAME="@default1050"></A>
<A NAME="@default1051"></A>
<A NAME="@default1052"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> addr = 'monty@python.org'
>>> uname, domain = addr.split('@')
</FONT></FONT>The return value from split is a list with two elements;
the first element is assigned to uname, the second to
domain.
<FONT COLOR=blue><FONT SIZE=4>>>> print uname monty >>> print domain python.org </FONT></FONT>
<A NAME="toc132"></A><A NAME="htoc146">12.3</A> Tuples as return values
<A NAME="@default1053"></A>
<A NAME="@default1054"></A> <A NAME="@default1055"></A>
<A NAME="@default1056"></A>
Strictly speaking, a function can only return one value, but
if the value is a tuple, the effect is the same as returning multiple values. For example, if you want to divide two integers and compute the quotient and remainder, it is inefficient to compute x/y and then x%y. It is better to compute
them both at the same time.
<A NAME="@default1057"></A>
The built-in function divmod takes two arguments and
returns a tuple of two values, the quotient and remainder.
You can store the result as a tuple:
<FONT COLOR=blue><FONT SIZE=4>>>> t = divmod(7, 3) >>> print t (2, 1) </FONT></FONT>
Or use tuple assignment to store the elements separately:
<A NAME="@default1058"></A> <A NAME="@default1059"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> quot, rem = divmod(7, 3) >>> print quot 2 >>> print rem 1 </FONT></FONT>
Here is an example of a function that returns a tuple:
<FONT COLOR=blue><FONT SIZE=4>def min_max(t):return min(t), max(t)</FONT></FONT>
max and min are built-in functions that find
the largest and smallest elements of a sequence. min_max
computes both and returns a tuple of two values.
<A NAME="@default1060"></A>
<A NAME="@default1061"></A> <A NAME="@default1062"></A>
<A NAME="@default1063"></A>
<A NAME="toc133"></A><A NAME="htoc147">12.4</A> Variable-length argument tuples
<A NAME="@default1064"></A>
<A NAME="@default1065"></A> <A NAME="@default1066"></A> <A NAME="@default1067"></A>
<A NAME="@default1068"></A>
Functions can take a variable number of arguments. A parameter
name that begins with * gathers arguments into a tuple. For example, printall
takes any number of arguments and prints them:
<FONT COLOR=blue><FONT SIZE=4>def printall(*args):
print args
</FONT></FONT>The gather parameter can have any name you like, but args is conventional. Here’s how the function works:
<FONT COLOR=blue><FONT SIZE=4>>>> printall(1, 2.0, '3') (1, 2.0, '3') </FONT></FONT>
You can combine the gather operator with required and positional arguments:
<FONT COLOR=blue><FONT SIZE=4>def pointless(required, optional=0, *args):
print required, optional, args
</FONT></FONT>Run this function with 1, 2, 3 and 4 or more arguments and make sure you understand what it does.
<A NAME="@default1069"></A> <A NAME="@default1070"></A>
The complement of gather is scatter. If you have a
sequence of values and you want to pass it to a function as multiple arguments, you can use the * operator. For example, divmod takes exactly two arguments; it
doesn’t work with a tuple:
<A NAME="@default1071"></A> <A NAME="@default1072"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> t = (7, 3) >>> divmod(t) TypeError: divmod expected 2 arguments, got 1 </FONT></FONT>
But if you scatter the tuple, it works:
<FONT COLOR=blue><FONT SIZE=4>>>> divmod(*t)(2, 1)
</FONT></FONT>
Many of the built-in functions use variable-length argument tuples. For example, max
and min can take any number of arguments:<A NAME="@default1073"></A> <A NAME="@default1074"></A> <A NAME="@default1075"></A> <A NAME="@default1076"></A>
<EM><FONT COLOR=blue><FONT SIZE=4>>>> max(1,2,3) 3 </FONT></FONT></EM>
But sum does not.
<A NAME="@default1077"></A> <A NAME="@default1078"></A>
<EM><FONT COLOR=blue><FONT SIZE=4>>>> sum(1,2,3) TypeError: sum expected at most 2 arguments, got 3 </FONT></FONT></EM>
Write a function called sumall that takes any number of arguments and returns their sum.
<A NAME="toc134"></A><A NAME="htoc148">12.5</A> Lists and tuples
<A NAME="@default1079"></A> <A NAME="@default1080"></A>
zip is a built-in function that takes two or more sequences and
“zips” them into a list<A NAME="text25" HREF="#note25">1</A> of tuples where each tuple contains one element from each
sequence.
<A NAME="@default1081"></A>
This example zips a string and a list:
<FONT COLOR=blue><FONT SIZE=4>>>> s = 'abc'
>>> t = [0, 1, 2]
>>> zip(s, t)
[('a', 0), ('b', 1), ('c', 2)]
</FONT></FONT>The result is a list of tuples where each tuple contains
a character from the string and the corresponding element from
the list.
<A NAME="@default1082"></A>
If the sequences are not the same length, the result has the length of the shorter one.
<FONT COLOR=blue><FONT SIZE=4>>>> zip('Anne', 'Elk')
[('A', 'E'), ('n', 'l'), ('n', 'k')]
</FONT></FONT>You can use tuple assignment in a for loop to traverse a list of tuples:
<A NAME="@default1083"></A>
<A NAME="@default1084"></A>
<A NAME="@default1085"></A>
<FONT COLOR=blue><FONT SIZE=4>t = [('a', 0), ('b', 1), ('c', 2)]
for letter, number in t:
print number, letter
</FONT></FONT>Each time through the loop, Python selects the next tuple in
the list and assigns the elements to letter and
number. The output of this loop is:
<A NAME="@default1086"></A>
<FONT COLOR=blue><FONT SIZE=4>0 a 1 b 2 c </FONT></FONT>
If you combine zip, for and tuple assignment, you get a
useful idiom for traversing two (or more) sequences at the same
time. For example, has_match takes two sequences, t1 and
t2, and returns True if there is an index i
such that t1[i] == t2[i]:
<A NAME="@default1087"></A>
<FONT COLOR=blue><FONT SIZE=4>def has_match(t1, t2):
for x, y in zip(t1, t2):
if x == y:
return True
return False
</FONT></FONT>If you need to traverse the elements of a sequence and their indices, you can use the built-in function enumerate:
<A NAME="@default1088"></A>
<A NAME="@default1089"></A>
<A NAME="@default1090"></A>
<FONT COLOR=blue><FONT SIZE=4>for index, element in enumerate('abc'):
print index, element
</FONT></FONT>The output of this loop is:
<FONT COLOR=blue><FONT SIZE=4>0 a1 b 2 c
</FONT></FONT>
Again.
<A NAME="toc135"></A><A NAME="htoc149">12.6</A> Dictionaries and tuples
<A NAME="@default1091"></A>
<A NAME="@default1092"></A> <A NAME="@default1093"></A>
<A NAME="@default1094"></A>
Dictionaries have a method called items that returns a list of tuples, where each tuple is a key-value pair<A NAME="text26" HREF="#note26">2</A>.
<FONT COLOR=blue><FONT SIZE=4>>>> d = {'a':0, 'b':1, 'c':2}
>>> t = d.items()
>>> print t
[('a', 0), ('c', 2), ('b', 1)]
</FONT></FONT>As you should expect from a dictionary, the items are in no particular order.
<A NAME="@default1095"></A>
Conversely, you can use a list of tuples to initialize a new dictionary:
<FONT COLOR=blue><FONT SIZE=4>>>> t = [('a', 0), ('c', 2), ('b', 1)]
>>> d = dict(t)
>>> print d
{'a': 0, 'c': 2, 'b': 1}
</FONT></FONT>Combining dict with zip yields a concise way to create a dictionary:
<A NAME="@default1096"></A>
<FONT COLOR=blue><FONT SIZE=4>>>> d = dict(zip('abc', range(3)))
>>> print d
{'a': 0, 'c': 2, 'b': 1}
</FONT></FONT>The dictionary method update also takes a list of tuples and adds them, as key-value pairs, to an existing dictionary.
<A NAME="@default1097"></A> <A NAME="@default1098"></A>
<A NAME="@default1099"></A> <A NAME="@default1100"></A>
Combining items, tuple assignment and for, you get the idiom for traversing the keys and values of a dictionary:
<FONT COLOR=blue><FONT SIZE=4>for key, val in d.items():
print val, key
</FONT></FONT>The output of this loop is:
<FONT COLOR=blue><FONT SIZE=4>0 a2 c 1 b
</FONT></FONT>
Again.
<A NAME="@default1101"></A> <A NAME="@default1102"></A>
It is common to use tuples as keys in dictionaries (primarily because
you can’t use lists). For example, a telephone directory might map from last-name, first-name pairs to telephone numbers. Assuming that we have defined last, first and number, we
could write:
<FONT COLOR=blue><FONT SIZE=4>directory[last,first] = number </FONT></FONT>
The expression in brackets is a tuple. We could use tuple assignment to traverse this dictionary.
<A NAME="@default1103"></A>
<FONT COLOR=blue><FONT SIZE=4>for last, first in directory:
print first, last, directory[last,first]
</FONT></FONT>This loop traverses the keys in directory, which are tuples. It
assigns the elements of each tuple to last and first, then
prints the name and corresponding telephone number.
There are two ways to represent tuples in a state diagram. The more
detailed version shows the indices and elements just as they appear in
a list. For example, the tuple ('Cleese', 'John') would appear:
<A NAME="@default1104"></A> <A NAME="@default1105"></A>
But in a larger diagram you might want to leave out the
details. For example, a diagram of the telephone directory might
appear:
Here the tuples are shown using Python syntax as a graphical shorthand.
The telephone number in the diagram is the complaints line for the BBC, so please don’t call it.
<A NAME="toc136"></A><A NAME="htoc150">12.7</A> Comparing tuples
<A NAME="@default1106"></A>
<A NAME="@default1107"></A> <A NAME="@default1108"></A>
<A NAME="@default1109"></A>
The comparison operators work with tuples and other sequences;
Python starts by comparing the first element from each sequence. If they are equal, it goes on to the next elements, and so on, until it finds elements that differ. Subsequent
elements are not considered (even if they are really big).
<FONT COLOR=blue><FONT SIZE=4>>>> (0, 1, 2) < (0, 3, 4) True >>> (0, 1, 2000000) < (0, 3, 4) True </FONT></FONT>
The sort function works the same way. It sorts
primarily by first element, but in the case of a tie, it sorts
by second element, and so on.
This feature lends itself to a pattern called DSU for
- Decorate
- a sequence by building a list of tuples with one or more sort keys preceding the elements from the sequence,
- Sort
- the list of tuples, and
- Undecorate
- by extracting the sorted elements of the sequence.
<A NAME="DSU"></A>
<A NAME="@default1110"></A> <A NAME="@default1111"></A> <A NAME="@default1112"></A>
<A NAME="@default1113"></A>
For example, suppose you have a list of words and you want to sort them from longest to shortest:
<FONT COLOR=blue><FONT SIZE=4>def sort_by_length(words):
t = []
for word in words:
t.append((len(word), word))
t.sort(reverse=True)
res = []
for length, word in t:
res.append(word)
return res
</FONT></FONT>The first loop builds a list of tuples, where each tuple is a word preceded by its length.
sort compares the first element, length, first, and
only considers the second element to break ties. The keyword argument
reverse=True tells sort to go in decreasing order.
<A NAME="@default1114"></A>
<A NAME="@default1115"></A>
<A NAME="@default1116"></A>
The second loop traverses the list of tuples and builds a list of words in descending order of length.
In this example, ties are broken by comparing words, so words with the same length appear in alphabetical order. For other applications you might want to break ties at random. Modify this example so that words with the same length appear in random order. Hint: see the random function in the
random module.<A NAME="@default1117"></A> <A NAME="@default1118"></A> <A NAME="@default1119"></A> <A NAME="@default1120"></A>
<A NAME="toc137"></A><A NAME="htoc151">12.8</A> Sequences of sequences
<A NAME="@default1121"></A>
I have focused on lists of tuples, but almost all of the examples in
this chapter also work with lists of lists, tuples of tuples, and tuples of lists. To avoid enumerating the possible combinations, it
is sometimes easier to talk about sequences of sequences.
In many contexts, the different kinds of sequences (strings, lists and
tuples) can be used interchangeably. So how and why do you choose one
over the others?
<A NAME="@default1122"></A>
<A NAME="@default1123"></A> <A NAME="@default1124"></A> <A NAME="@default1125"></A>
<A NAME="@default1126"></A>
To start with the obvious, strings are more limited than other
sequences because the elements have to be characters. They are also immutable. If you need the ability to change the characters in a string (as opposed to creating a new string), you might
want to use a list of characters instead.
Lists are more common than tuples, mostly because they are mutable. But there are a few cases where you might prefer tuples:
- In some contexts, like a return statement, it is
syntactically simpler to create a tuple than a list. In other
contexts, you might prefer a list. - If you want to use a sequence as a dictionary key, you have to use an immutable type like a tuple or string.
- If you are passing a sequence as an argument to a function, using tuples reduces the potential for unexpected behavior due to aliasing.
Because tuples are immutable, they don’t provide methods
like sort and reverse, which modify existing lists. But Python provides the built-in functions sorted and reversed, which take any sequence as a parameter and return a new list with the same elements in a different
order.
<A NAME="@default1127"></A>
<A NAME="@default1128"></A> <A NAME="@default1129"></A>
<A NAME="@default1130"></A>
<A NAME="toc138"></A><A NAME="htoc152">12.9</A> Debugging
<A NAME="@default1131"></A>
<A NAME="@default1132"></A> <A NAME="@default1133"></A>
<A NAME="@default1134"></A>
Lists, dictionaries and tuples are known generically as data
structures; in this chapter we are starting to see compound data structures, like lists of tuples, and dictionaries that contain tuples as keys and lists as values. Compound data structures are useful, but they are prone to what I call shape errors; that is, errors caused when a data structure has the wrong type, size or composition. For example, if you are expecting a list with one integer and I
give you a plain old integer (not in a list), it won’t work.
<A NAME="@default1135"></A> <A NAME="@default1136"></A>
To help debug these kinds of errors, I have written a module
called structshape that provides a function, also called structshape, that takes any kind of data structure as an argument and returns a string that summarizes its shape.
You can download it from thinkpython.com/code/structshape.py
Here’s the result for a simple list:
<FONT COLOR=blue><FONT SIZE=4>>>> from structshape import structshape >>> t = [1,2,3] >>> print structshape(t) list of 3 int </FONT></FONT>
A fancier program might write “list of 3 ints,” but it was easier not to deal with plurals. Here’s a list of lists:
<FONT COLOR=blue><FONT SIZE=4>>>> t2 = [[1,2], [3,4], [5,6]] >>> print structshape(t2) list of 3 list of 2 int </FONT></FONT>
If the elements of the list are not the same type, structshape groups them, in order, by type:
<FONT COLOR=blue><FONT SIZE=4>>>> t3 = [1, 2, 3, 4.0, '5', '6', [7], [8], 9] >>> print structshape(t3) list of (3 int, float, 2 str, 2 list of int, int) </FONT></FONT>
Here’s a list of tuples:
<FONT COLOR=blue><FONT SIZE=4>>>> s = 'abc'>>> lt = zip(t, s) >>> print structshape(lt) list of 3 tuple of (int, str)
</FONT></FONT>
And here’s a dictionary with 3 items that map integers to strings.
<FONT COLOR=blue><FONT SIZE=4>>>> d = dict(lt)>>> print structshape(d) dict of 3 int->str
</FONT></FONT>
If you are having trouble keeping track of your data structures, structshape can help.
<A NAME="toc139"></A><A NAME="htoc153">12.10</A> Glossary
- tuple:
- An immutable sequence of elements. <A NAME="@default1137"></A>
- tuple assignment:
- An assignment with a sequence on the right side and a tuple of variables on the left. The right side is evaluated and then its elements are assigned to the variables on the left. <A NAME="@default1138"></A> <A NAME="@default1139"></A>
- gather:
- The operation of assembling a variable-length argument tuple. <A NAME="@default1140"></A>
- scatter:
- The operation of treating a sequence as a list of arguments. <A NAME="@default1141"></A>
- DSU:
- Abbreviation of “decorate-sort-undecorate,” a pattern that involves building a list of tuples, sorting, and extracting part of the result. <A NAME="@default1142"></A>
- data structure:
- A collection of related values, often organized in lists, dictionaries, tuples, etc. <A NAME="@default1143"></A>
- shape (of a data structure):
- A summary of the type, size and composition of a data structure. <A NAME="@default1144"></A>
<A NAME="toc140"></A><A NAME="htoc154">12.11</A> Exercises
Write a function called most_frequent that takes a string and
prints the letters in decreasing order of frequency. Find text
samples from several different languages and see how letter frequency
varies between languages. Compare your results with the tables at
<A NAME="@default1145"></A> <A NAME="@default1146"></A>
<A NAME="@default1147"></A> <A NAME="@default1148"></A>
More anagrams!
- Write a program
that reads a word list from a file (see Section <A HREF="book010.html#wordlist">9.1</A>) and
prints all the sets of words that are anagrams.Here is an example of what the output might look like:
<EM><FONT COLOR=blue><FONT SIZE=4>['deltas', 'desalt', 'lasted', 'salted', 'slated', 'staled'] ['retainers', 'ternaries'] ['generating', 'greatening'] ['resmelts', 'smelters', 'termless'] </FONT></FONT></EM>
Hint: you might want to build a dictionary that maps from a
set of letters to a list of words that can be spelled with those letters. The question is, how can you represent the set of
letters in a way that can be used as a key? - Modify the previous program so that it prints the largest set
of anagrams first, followed by the second largest set, and so on.
<A NAME="@default1149"></A> <A NAME="@default1150"></A>
- In Scrabble a “bingo” is when you play all seven tiles in
your rack, along with a letter on the board, to form an eight-letter word. What set of 8 letters forms the most possible bingos?
Hint: there are seven.<A NAME="@default1151"></A>
- Two words form a “metathesis pair” if you can transform one
into the other by swapping two letters<A NAME="text27" HREF="#note27">3</A>; for example, “converse” and “conserve.” Write a program that finds all of the metathesis pairs in the dictionary. Hint: don’t test all pairs
of words, and don’t test all possible swaps.You can download a solution from thinkpython.com/code/anagram_sets.py.
<A NAME="@default1152"></A> <A NAME="@default1153"></A>
Here’s another Car Talk Puzzler<A NAME="text28" HREF="#note28">4</A>:
What is the longest English word, that remains a valid English word,
as you remove its letters one at a time?
Now, letters can be removed from either end, or the middle, but you can’t rearrange any of the letters. Every time you drop a letter, you wind up with another English word. If you do that, you’re eventually going to wind up with one letter and that too is going to be an English word—one that’s found in the dictionary. I want to know what’s the longest word and how many letters does it have?
I’m going to give you a little modest example: Sprite. Ok? You start
off with sprite, you take a letter off, one from the interior of the word, take the r away, and we’re left with the word spite, then we take the e off the end, we’re left with spit, we take the s off, we’re left with pit, it, and I.
<A NAME="@default1154"></A> <A NAME="@default1155"></A>
Write a program to find all words that can be reduced in this way, and then find the longest one.
This exercise is a little more challenging than most, so here are some suggestions:
- You might want to write a function that takes a word and
computes a list of all the words that can be formed by removing one
letter. These are the “children” of the word.<A NAME="@default1156"></A> <A NAME="@default1157"></A>
- Recursively, a word is reducible if any of its children
are reducible. As a base case, you can consider the empty
string reducible. - The wordlist I provided, words.txt, doesn’t contain single letter words. So you might want to add “I”, “a”, and the empty string.
- To improve the performance of your program, you might want to memoize the words that are known to be reducible.
You can see my solution at thinkpython.com/code/reducible.py.
- <A NAME="note25" HREF="#text25">1</A>
- In Python 3.0, zip returns an iterator of tuples, but for most purposes, an iterator behaves like a list.
- <A NAME="note26" HREF="#text26">2</A>
- This behavior is slightly different in Python 3.0.
- <A NAME="note27" HREF="#text27">3</A>
- This exercise is inspired by an example at puzzlers.org.
- <A NAME="note28" HREF="#text28">4</A>
- www.cartalk.com/content/puzzler/transcripts/200651
<A HREF="book012.html"><IMG SRC="previous_motif.gif" ALT="Previous"></A> <A HREF="index.html"><IMG SRC="contents_motif.gif" ALT="Up"></A> <A HREF="book014.html"><IMG SRC="next_motif.gif" ALT="Next"></A> </BODY> </HTML>