12.15 双重列表:数据表

    考虑数据如何存储在程序中时,可以用图直观地表示,这很有用。

    变量有一个值。

    空标题文档 - 图1

    列表就像是把一行值串在一起。

    空标题文档 - 图2

    有时还需要一个包含行和列的表。

    空标题文档 - 图3

    如何保存数据表呢?我们已经知道,列表中包含多个元素,可以把每个学生的成绩放在一个列表中,像这样:

    >>> joeMarks = [55, 63, 77, 81]
    >>> tomMarks = [65, 61, 67, 72]
    >>> bethMarks = [97, 95, 92, 88]

    或者对应每个课程使用一个列表,如下:

    >>> mathMarks = [55, 65, 97]
    >>> scienceMarks = [63, 61, 95]
    >>> readingMarks = [77, 67, 92]
    >>> spellingMarks = [81, 72, 88]

    不过我们可能希望把所有数据都收集到一个数据结构中。

    术语箱
    数据结构(data structure)是一种在程序中收集、存储或表示数据的方法。数据结构包括变量、列表和其他一些我们还没有讨论到的内容。实际上,数据结构这个词就表示程序中数据的组织方式。

    要为我们的成绩建立一个数据结构,可以这样做:

    >>> classMarks = [joeMarks, tomMarks, bethMarks]
    >>> print classMarks
    [[55, 63, 77, 81], [65, 61, 67, 72], [97, 95, 92, 88]]

    这会得到一个元素列表,其中每个元素本身又是一个列表。我们创建了一个“列表的列表”(list of list),也就是双重列表。classMarks 列表中的每个元素本身又都是一个列表。

    还可以直接创建 classMarks,而不需要先创建 joeMarkstomMarksbethMarks,如下:

    >>> classMarks = [ [55,63,77,81], [65,61,67,72], [97,95,92,88] ]
    >>> print classMarks
    [[55, 63, 77, 81], [65, 61, 67, 72], [97, 95, 92, 88]]

    现在来显示我们的数据结构:classMarks 有 3 个元素,每个元素分别对应一个学生。所以可以使用 in 来循环处理:

    >>> for studentMarks in classMarks:
    print studentMarks

    [55, 63, 77, 81]
    [65, 61, 67, 72]
    [97, 95, 92, 88]

    这里我们对名为 classMarks 的列表完成循环处理。循环变量是 studentMarks。每次循环时,会打印列表中的一个元素。这里的每一个元素分别是一个学生的成绩,它本身也是一个列表。(前面创建过这些学生列表。)

    可以注意到,这看上去与前一页的表很类似,所以我们提出的这种数据结构可以把所有数据都保存在一个地方。

    从表获取一个值

    怎么得到这个表(也就是双重列表)中的值呢?我们已经知道,第一个学生的成绩(joeMarks)在一个列表中,而这个列表本身是 classMarks 中的第一个元素。

    下面来检查一下:

    >>> print classMarks[0]
    [55, 63, 77, 81]

    classMarks[0] 是 Joe 的 4 门课程成绩的一个列表。现在我们想从 classMarks[0] 得到一个值。怎么做呢?可以使用第二个索引。

    如果希望得到他的第三个成绩(阅读课成绩),也就是索引 2,可以这样做:

    >>> print classMarks[0][2]
    77

    这会给出 classMarks 中的第一个元素(索引 0),也就是 Joe 的成绩列表,以及这个列表中的第三个元素(索引 2),这正是他的阅读课成绩。看到一个名字后面带着两组中括号时,比如说 classMarks[0][2],这往往表示一个双重列表。

    空标题文档 - 图4

    classMarks 列表并不知道 Joe、Tom 和 Beth 这些名字,也不知道数学(Math)、科学(Science)、阅读(Reading)和拼写(Spelling)这些课程。这里之所以这样标,是因为我们知道想要在这个列表中储存什么信息。不过,对于 Python 来说,它们只是列表中一些已经编号的位置而已。这就像邮局里编号的邮箱。邮箱上没有名字,只有编号。邮递员只负责明确哪封信归哪个邮箱,而你知道哪个邮箱是你的。

    空标题文档 - 图5

    要对 classMarks 表加标签,一种更准确的方法应该是这样:

    空标题文档 - 图6

    现在可以更容易地看出成绩 77 存储在 classMarks[0][2] 中。

    如果编写一个程序使用 classMarks 存储我们的数据,就必须知道哪些数据存储在哪一行哪一列。就像邮递员一样,我们的任务是明确哪个位置属于哪个数据。