Python:5. Data Structures(数据结构)

5. 数据结构

本章更详细地描述了您已经了解的一些内容, 并添加了一些新的东西。

5.1. 更多关于列表的信息
列表数据类型具有更多方法。以下是列表的所有方法 对象:

列表。追加(x)
将项目添加到列表末尾。等效于 。a[len(a):] = [x]

列表。扩展(可迭代))
通过追加可迭代对象中的所有项来扩展列表。等效于 。a[len(a):] = iterable

列表。插入(I, X)
在给定位置插入项目。第一个参数是 元素,因此插入在前面 列表,等效于 。a.insert(0, x)a.insert(len(a), x)a.append(x)

列表。删除(x)
从列表中删除值等于 x 的第一项。如果没有此类项目,它会引发 ValueError。

列表。流行([i])
删除列表中给定位置的项目,然后将其返回。如果没有索引 ,删除并返回列表中的最后一项。(的 方法签名中 i 两边的方括号表示参数 是可选的,而不是您应该在该位置键入方括号。你 将在 Python 库参考中频繁看到此表示法。a.pop()

列表。清楚()
从列表中删除所有项目。等效于 。del a[:]

列表。索引(x[, 开始[, 结束]])
返回值等于 x 的第一项的列表中的从零开始的索引。 如果没有此类项目,则引发 ValueError。

可选参数的开头和结尾解释为在切片中 表示法,用于将搜索限制为 列表。返回的索引是相对于完整 序列而不是开始参数。

列表。计数(x)
返回 x 出现在列表中的次数。

列表。sort(*, 键=无, 反向=假)
就地对列表的项目进行排序(参数可用于排序 自定义,请参阅 sorted() 了解它们的解释)。

列表。反向()
就地反转列表的元素。

列表。复制()
返回列表的浅表副本。等效于 。a[:]

使用大多数列表方法的示例:

>>>
fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
fruits.count('apple')
2
fruits.count('tangerine')
0
fruits.index('banana')
3
fruits.index('banana', 4)  # Find next banana starting at position 4
6
fruits.reverse()
fruits
['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange']
fruits.append('grape')
fruits
['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange', 'grape']
fruits.sort()
fruits
['apple', 'apple', 'banana', 'banana', 'grape', 'kiwi', 'orange', 'pear']
fruits.pop()
'pear'

您可能已经注意到,像 或 只有修改列表才没有打印返回值 – 它们返回默认值。1 这是所有可变数据结构的设计原则 蟒。insertremovesortNone

您可能会注意到的另一件事是,并非所有数据都可以排序或 比较。例如,不排序,因为 整数不能与字符串进行比较,无不能与字符串进行比较 其他类型。此外,有些类型没有定义 排序关系。例如,不是有效的 比较。[None, ‘hello’, 10]3+4j < 5+7j

5.1.1. 使用列表作为堆栈
列表方法使得将列表用作堆栈变得非常容易,其中最后一个 添加的元素是检索到的第一个元素(“后进先出”)。要添加 项到堆栈顶部,使用 .要从 堆栈顶部,不使用显式索引。例如:append()pop()

>>>
stack = [3, 4, 5]
stack.append(6)
stack.append(7)
stack
[3, 4, 5, 6, 7]
stack.pop()
7
stack
[3, 4, 5, 6]
stack.pop()
6
stack.pop()
5
stack
[3, 4]

5.1.2. 使用列表作为队列
也可以使用列表作为队列,其中添加的第一个元素是 检索到的第一个元素(“先进先出”);但是,列表不是 为此目的有效。虽然从列表末尾追加和弹出是 快速,从列表开头进行插入或弹出很慢(因为所有 其他元素必须移动一个)。

要实现队列,请使用 collections.deque,它旨在 从两端快速追加和弹出。例如:

>>>
from collections import deque
queue = deque(["Eric", "John", "Michael"])
queue.append("Terry")           # Terry arrives
queue.append("Graham")          # Graham arrives
queue.popleft()                 # The first to arrive now leaves
'Eric'
queue.popleft()                 # The second to arrive now leaves
'John'
queue                           # Remaining queue in order of arrival
deque(['Michael', 'Terry', 'Graham'])

5.1.3. 列表推导
列表推导式提供了一种创建列表的简洁方法。 常见的应用程序是制作新列表,其中每个元素都是 某些操作应用于另一个序列或可迭代对象的每个成员,或 创建满足特定条件的元素的子序列。

例如,假设我们要创建一个正方形列表,例如:

>>>
squares = []
for x in range(10):
    squares.append(x**2)

squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

请注意,这会创建(或覆盖)一个名为仍然存在的变量 循环完成后。我们可以计算正方形列表,而无需任何 使用以下方面的副作用:x

squares = list(map(lambda x: x**2, range(10)))

或者,等效地:

squares = [x**2 for x in range(10)]

这更简洁易读。

列表推导式由包含后跟表达式的括号组成 通过子句,然后是零个或多个或子句。结果将是计算表达式后产生的新列表 在它后面的 和 条款的上下文中。 例如,此 listcomp 组合了两个列表的元素(如果它们不是) 平等:forforifforif

>>>
[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
它相当于:

>>>
combs = []
for x in [1,2,3]:
    for y in [3,1,4]:
        if x != y:
            combs.append((x, y))

combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

请注意 for 和 if 语句的顺序是 这两个代码段相同。

如果表达式是元组(例如上一个示例中的元组), 它必须括起来。(x, y)

>>>
vec = [-4, -2, 0, 2, 4]
# create a new list with the values doubled
[x*2 for x in vec]
[-8, -4, 0, 4, 8]
# filter the list to exclude negative numbers
[x for x in vec if x >= 0]
[0, 2, 4]
# apply a function to all the elements
[abs(x) for x in vec]
[4, 2, 0, 2, 4]
# call a method on each element
freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
[weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']
# create a list of 2-tuples like (number, square)
[(x, x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
# the tuple must be parenthesized, otherwise an error is raised
[x, x**2 for x in range(6)]
  File "<stdin>", line 1
    [x, x**2 for x in range(6)]
     ^^^^^^^
SyntaxError: did you forget parentheses around the comprehension target?
# flatten a list using a listcomp with two 'for'
vec = [[1,2,3], [4,5,6], [7,8,9]]
[num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

列表推导式可以包含复杂的表达式和嵌套函数:

>>>
from math import pi
[str(round(pi, i)) for i in range(1, 6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']

5.1.4. 嵌套列表推导
列表推导式中的初始表达式可以是任意表达式, 包括另一个列表理解。

考虑以下示例,该示例将 3x4 矩阵实现为 3 长度为 4 的列表:

>>>
matrix = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
]

以下列表推导将转置行和列:

>>>
[[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

正如我们在上一节中看到的,内部列表推导式是在 后面的 for 的上下文,所以这个例子是 相当于:

>>>
transposed = []
for i in range(4):
    transposed.append([row[i] for row in matrix])

transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

反过来,这与:

>>>
transposed = []
for i in range(4):
    # the following 3 lines implement the nested listcomp
    transposed_row = []
    for row in matrix:
        transposed_row.append(row[i])
    transposed.append(transposed_row)

transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

在现实世界中,您应该更喜欢内置函数而不是复杂的流语句。 zip() 函数对于这个用例来说会做得很好:

>>>
list(zip(*matrix))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

有关此行中星号的详细信息,请参阅解压缩参数列表。

5.2. 声明del
有一种方法可以从给定索引而不是其索引的列表中删除项目 值:DEL 语句。这与方法不同 返回一个值。该语句还可用于删除 从列表中切片或清除整个列表(我们之前通过分配这样做 的空列表到切片)。例如:pop()del

>>>
a = [-1, 1, 66.25, 333, 333, 1234.5]
del a[0]
a
[1, 66.25, 333, 333, 1234.5]
del a[2:4]
a
[1, 66.25, 1234.5]
del a[:]
a
[]

del 还可用于删除整个变量:

>>>
del a

在后面引用名称是一个错误(至少在另一个值之前 被分配给它)。我们稍后会发现 del 的其他用途。a

5.3. 元组和序列
我们看到列表和字符串具有许多通用属性,例如索引和 切片操作。它们是序列数据类型的两个示例(请参阅序列类型 — 列表、元组、范围)。由于Python是一种不断发展的语言,因此其他序列数据 可以添加类型。还有另一种标准序列数据类型:元组。

元组由许多以逗号分隔的值组成,例如:

>>>
t = 12345, 54321, 'hello!'
t[0]
12345
t
(12345, 54321, 'hello!')
# Tuples may be nested:
u = t, (1, 2, 3, 4, 5)
u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
# Tuples are immutable:
t[0] = 88888
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
# but they can contain mutable objects:
v = ([1, 2, 3], [3, 2, 1])
v
([1, 2, 3], [3, 2, 1])

如您所见,在输出元组上总是括在括号中,以便嵌套 元组被正确解释;它们可以是带或不带周围环境的输入 括号,尽管括号通常是必需的(如果元组是 较大表达式的一部分)。无法分配给个人 元组的项,但是可以创建包含可变元组的元组 对象,例如列表。

尽管元组可能看起来与列表相似,但它们通常用于不同的 情况和不同的目的。 元组是不可变的,通常包含 通过解包(请参阅本节后面的内容)或索引访问的元素 (甚至在命名元组的情况下按属性)。 列表是可变的,它们的元素通常是同质的,并且 通过循环访问列表。

一个特殊的问题是构造包含 0 或 1 项的元组:该 语法有一些额外的怪癖来适应这些。构造空元组 由一对空括号;具有一个项目的元组由 在值后面加上逗号(将单个值括起来是不够的 在括号中)。丑陋,但有效。例如:

>>>
empty = ()
singleton = 'hello',    # <-- note trailing comma
len(empty)
0
len(singleton)
1
singleton
('hello',)

该语句是元组打包的一个示例: 值,并打包在一个元组中。 反向操作也是可能的:t = 12345, 54321, 'hello!‘1234554321’hello!’

>>>
x, y, z = t

这被称为,足够恰当的序列解包,适用于任何 右侧的序列。序列解包要求有 等号左侧有许多变量,因为 序列。请注意,多重赋值实际上只是元组的组合 包装和顺序拆包。

5.4. 集合
Python 还包括集合的数据类型。集合是无序集合 没有重复的元素。基本用途包括成员资格测试和 消除重复条目。集合对象还支持数学运算 如并集、交集、差分和对称差分。

大括号或 set() 函数可用于创建集合。注:至 创建一个你必须使用的空集,而不是 ;后者创建了一个 空字典,我们将在下一节中讨论的数据结构。set(){}

下面是一个简短的演示:

>>>
basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
print(basket)                      # show that duplicates have been removed
{'orange', 'banana', 'pear', 'apple'}
'orange' in basket                 # fast membership testing
True
'crabgrass' in basket
False

# Demonstrate set operations on unique letters from two words

a = set('abracadabra')
b = set('alacazam')
a                                  # unique letters in a
{'a', 'r', 'b', 'c', 'd'}
a - b                              # letters in a but not in b
{'r', 'd', 'b'}
a | b                              # letters in a or b or both
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
a & b                              # letters in both a and b
{'a', 'c'}
a ^ b                              # letters in a or b but not both
{'r', 'd', 'b', 'm', 'z', 'l'}

与列出推导类似,设置推导 还支持:

>>>
a = {x for x in 'abracadabra' if x not in 'abc'}
a
{'r', 'd'}

5.5. 词典
Python 内置的另一个有用的数据类型是字典(参见映射类型 — dict)。词典有时以其他语言找到,如 “关联记忆”或“关联数组”。与序列不同,序列是 字典按一系列数字编制索引,按键索引,键可以是 任何不可变类型;字符串和数字始终可以是键。可以使用元组 如果它们仅包含字符串、数字或元组,则作为键;如果元组包含 任何可变对象,无论是直接或间接的,它都不能用作键。 您不能将列表用作键,因为可以使用索引就地修改列表 赋值、切片赋值或方法(如 和 )。append()extend()

最好将字典视为一组键:值对, 要求键是唯一的(在一个字典中)。一对 大括号创建一个空字典:。放置一个逗号分隔的列表 大括号内的键:值对将初始键:值对添加到 字典;这也是字典在输出上的编写方式。{}

字典上的主要操作是存储带有一些键的值和 提取给定键的值。也可以删除键:值 与 配对。如果使用已在使用的密钥进行存储,则旧的 与该键关联的值将被遗忘。提取值是错误的 使用不存在的密钥。del

对字典执行将返回所有键的列表 在字典中按插入顺序使用(如果要对其进行排序,只需改用)。要检查单个键是否位于 字典中,使用 in 关键字。list(d)sorted(d)

下面是一个使用字典的小示例:

>>>
tel = {'jack': 4098, 'sape': 4139}
tel['guido'] = 4127
tel
{'jack': 4098, 'sape': 4139, 'guido': 4127}
tel['jack']
4098
del tel['sape']
tel['irv'] = 4127
tel
{'jack': 4098, 'guido': 4127, 'irv': 4127}
list(tel)
['jack', 'guido', 'irv']
sorted(tel)
['guido', 'irv', 'jack']
'guido' in tel
True
'jack' not in tel
False

dict() 构造函数直接从 键值对:

>>>
dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'guido': 4127, 'jack': 4098}

此外,字典推导可用于创建字典 任意键和值表达式:

>>>
{x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}

当键是简单的字符串时,有时使用 关键字参数:

>>>
dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'guido': 4127, 'jack': 4098}

5.6. 循环技术
遍历字典时,键和对应的值可以是 使用该方法同时检索。items()

>>>
knights = {'gallahad': 'the pure', 'robin': 'the brave'}
for k, v in knights.items():
    print(k, v)

gallahad the pure
robin the brave

循环遍历序列时,位置索引和相应的值可以 同时使用 enumerate() 函数检索。

>>>
for i, v in enumerate(['tic', 'tac', 'toe']):
    print(i, v)

0 tic
1 tac
2 toe

要同时循环访问两个或多个序列,可以将条目配对 使用 zip() 函数。

>>>
questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for q, a in zip(questions, answers):
    print('What is your {0}?  It is {1}.'.format(q, a))

What is your name?  It is lancelot.
What is your quest?  It is the holy grail.
What is your favorite color?  It is blue.

要反向循环序列,请先在正向中指定序列 方向,然后调用 reversed() 函数。

>>>
for i in reversed(range(1, 10, 2)):
    print(i)

9
7
5
3
1

要按排序顺序循环序列,请使用 sorted() 函数 返回一个新的排序列表,同时保持源不变。

>>>
basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for i in sorted(basket):
    print(i)

apple
apple
banana
orange
orange
pear

在序列上使用 set() 可以消除重复元素。在序列上使用sorted()与set()结合使用是一种惯用语 按排序顺序循环序列的唯一元素的方法。

>>>
basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for f in sorted(set(basket)):
    print(f)

apple
banana
orange
pear

有时,当您循环访问列表时,更改列表很诱人; 但是,创建新列表通常更简单、更安全。

>>>
import math
raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
filtered_data = []
for value in raw_data:
    if not math.isnan(value):
        filtered_data.append(value)

filtered_data
[56.2, 51.7, 55.3, 52.5, 47.8]

5.7. 更多关于条件的信息
和语句中使用的条件可以包含任何 运算符,而不仅仅是比较。whileif

比较运算符和是成员资格测试 确定值是否在容器中(或不在容器中)。运算符并比较两个对象是否确实是同一对象。都 比较运算符具有相同的优先级,低于所有 数字运算符。innot inisis not

比较可以链接。例如,测试是否 小于,而且等于.a < b == cabbc

可以使用布尔运算符和 、 和 来组合比较 比较(或任何其他布尔表达式)的结果可能被否定 跟。这些的优先级低于比较运算符;之间 它们具有最高优先级和最低优先级,因此等效于 .与往常一样,括号 可用于表达所需的组合物。andornotnotorA and not B or C(A and (not B)) or C

布尔运算符和所谓的短路运算符:它们的参数从左到右计算,并评估 一旦确定结果,就会停止。例如,如果和 真但假,不计算表达式。当用作一般值而不是布尔值时,返回值 短路运算符是最后一个计算的参数。andorACBA and B and CC

可以分配比较或其他布尔表达式的结果 到变量。例如

>>>
string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
non_null = string1 or string2 or string3
non_null
'Trondheim'

请注意,在 Python 中,与 C 不同,必须在表达式内完成赋值 明确与海象操作员. 这避免了 C 程序中遇到的一类常见问题:在预期时键入表达式。:====

5.8. 比较序列和其他类型
序列对象通常可以与具有相同序列的其他对象进行比较 类型。比较使用字典顺序:前两个 比较项目,如果它们不同,这将决定 比较;如果它们相等,则比较接下来的两个项目,依此类推,直到 任一序列都已用尽。如果要比较的两个项目是它们自己 相同类型的序列,进行词典比较 递 归。如果两个序列的所有项目比较相等,则序列为 被认为是平等的。如果一个序列是另一个序列的初始子序列,则 较短的序列是较小(较小)的序列。词典排序 字符串使用 Unicode 码位编号对单个字符进行排序。 相同类型序列之间的比较的一些示例:

(1, 2, 3)              < (1, 2, 4)
[1, 2, 3]              < [1, 2, 4]
'ABC' < 'C' < 'Pascal' < 'Python'
(1, 2, 3, 4)           < (1, 2, 4)
(1, 2)                 < (1, 2, -1)
(1, 2, 3)             == (1.0, 2.0, 3.0)
(1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)

请注意,将不同类型的对象与 or 进行比较是合法的 前提是对象具有适当的比较方法。例如 混合数值类型根据其数值进行比较,因此 0 等于 0.0等否则,与其提供任意排序,不如 解释器将引发 TypeError 异常。<>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值