Before, I said that lists or tuples can be sequences of anything. If that's true, then lists can contain other lists or tuples, and tuples can contain other tuples or lists. Well, they can, and when they do, they're called nested sequences. Nested sequences are sequences inside other sequences. Nested sequences are a great way to organize more complex collections of information.
Although the term sounds like another cryptic piece of computer jargon, I bet you create and use nested sequences all the time. Let me give you an example. Say you're making a holiday shopping list. You start by making a list of names. Under each name, you list a few possible gifts. Well, you've just created a nested sequence: you have a list of names and each name represents a list of gifts. That's all there is to it.
The last program, High Scores, uses only scores. But most high score lists store a name along with a score. That's what this new version does. It also has a few other improvements. It automatically sorts the scores and even limits the list to just the top five. Figure 5.7 shows a sample run.
Figure 5.7: The new and improved version of High Scores stores a name with a score through nested sequences.
You create a nested list or tuple like always: type each element, followed by a comma. The difference with nested sequences is that you include entire lists or tuples as elements. Here's an example:
>>> nested = ["first", ("second", "third"), ["fourth", "fifth", "sixth"]] >>> print nested ['first', ('second', 'third'), ['fourth', 'fifth', 'sixth']]
So, although you see six strings here, nested has only three elements. The first element is the string "first", the second element is the tuple ("second", "third"), and the third element is the list ["fourth", "fifth", "sixth"].
While you can create a list or tuple with any number of lists and tuples, useful nested sequences often have a consistent pattern. Take a look at the next example:
>>> scores = [("Moe", 1000), ("Larry", 1500), ("Curly", 3000)] >>> print scores [('Moe', 1000), ('Larry', 1500), ('Curly', 3000)]
scores is a list with three elements. Each element is a tuple. Each tuple has exactly two elements, a string and a number. This kind of uniform structure makes for the most useful nested sequences.
This sequence, by the way, represents a high score table with names and scores (like a real high score table should!). In this particular instance, Moe got a score of 1,000; Larry got 1,500; and Curly got a high score of 3,000.
TRAP | Although you can create nested sequences inside nested sequences many times over, as in the following example, this usually isn't a good idea.
nested = ("deep", ("deeper", ("deepest", "still deepest"))) Things can get confusing fast. Even experienced programmers rarely use sequences more than a level or two deep. For most programs you'll write, one level of nesting (like the scores list you just saw) is really all you'll need. |
You access elements of a nested sequence just like any other sequence, through indexing:
>>> scores = [("Moe", 1000), ("Larry", 1500), ("Curly", 3000)] >>> print scores[0] ('Moe', 1000) >>> print scores[1] ('Larry', 1500) >>> print scores[2] ('Curly', 3000)
Each element is a tuple, so that's exactly what you get when you access one. But what if you want to access one of the elements of one of the tuples? One way is to assign the tuple to a variable and index it, as in:
>>> a_score = scores[2] >>> print a_score ('Curly', 3000) >>> print a_score[0] Curly
But there's a direct way to access "Curly" right from scores:
>>> print scores[2][0] Curly
By supplying two indices with scores[2][0], you're telling the computer to go get the element from scores at position 2 (which is ("Curly", 3000)) and then, from that, to get the element at position 0 (which is "Curly"). You can use this kind of multiple indexing with nested sequences to get directly to a nested element.
If you know how many elements are in a sequence, you can assign each to its own variable in a single line of code:
>>> name, score = ("Shemp", 175) >>> print name Shemp >>> print score 175
This is called unpacking and works with any sequence type. Just remember to use the same number of variables as elements in the sequence, because otherwise you'll generate an error.
Just as in the original High Scores program, I set up the variables and while loop. As before, if the user enters 0, the computer prints "Good-bye.":
# High Scores 2.0 # Demonstrates nested sequences # Michael Dawson - 1/31/03 scores = [] choice = None while choice != "0": print \ """ High Scores Keeper 0 - Quit 1 - List Scores 2 - Add a Score """ choice = raw_input("Choice: ") print # exit if choice == "0": print "Good-bye."
If the user enters 1, the computer goes through each element in scores and unpacks the score and name into the variables score and name. Then the computer prints them out.
# display high-score table elif choice == "1": print "NAME\tSCORE" for entry in scores: score, name = entry print name, "\t", score
If the user enters 2, the computer lets the user enter a new score and name. With these two values, the computer creates a tuple, entry. I chose to store the score first in this tuple because I wanted the entries to be sorted by score, then name. Next, the computer appends this new high score entry to the list. The computer sorts the list and reverses it so that the highest scores are first. The final statement slices and assigns the list so that only the top five scores are kept.
# add a score elif choice == "2": name = raw_input("What is the player's name?: ") score = int(raw_input("What score did the player get?: ")) entry = (score, name) scores.append(entry) scores.sort() scores.reverse() # want the highest number first scores = scores[:5] # keep only top 5 scores
If the user enters something other than 0, 1, or 2, the else clause catches it. The program lets the user know that the choice wasn't understood.
# some unknown choice else: print "Sorry, but", choice, "isn't a valid choice."
After the user enters 0 to exit, the loop ends and the program waits for the user:
raw_input("\n\nPress the enter key to exit.")