数据结构是Python中一个很重要的概念,是以某种方式(如通过编号)组合起来的数据元素(如数字、字符乃至其他数据结构)的集合。
在Python中,最基本的数据结构是序列(sequence)。
- 序列中的每个元素都有编号,及其位置或索引,其中的第一个元素的索引为0,第二个元素位的索引为1,依此类推
- 在有些编程语言中,从1开始给序列中的元素编号,但从0开始指出相对于序列开头的偏移量。
- 同时可以回绕到序列末尾,用负索引表示序列末尾元素的位置,-1表示序列最后一个元素的索引,-2表示序列倒数第二个元素的索引...
Python内置了多种序列:
- 列表
- 元组
- 字符串
列表和元组的主要不同在于,列表是可以修改的,元组不可以修改。
列表适用于需要中途添加元素的情形,而元组适用于出于某种考虑需要禁止修改序列的情形。
在需要处理一系列值时,序列很有用。
例如在数据库中,可以使用序列来表示人,第一个元素为人名,第二个元素为年龄...
序列中还可以包含其他序列,因此可以创建一个由数据库中所保存的人员组成的列表
>>>
>>> edward = ['Edward Gumby', 42, 'male']
>>> john = ['John Smith', 50, 'female']
>>> database = [edward, john]
>>> database
[['Edward Gumby', 42, 'male'], ['John Smith', 50, 'female']]
>>>
Python支持一种数据结构的基本概念,名为容器(container):
- 容器基本上就是可包含其他对象的对象
- 两种主要的容器是序列(如列表和元组)和映射(字典)。在序列中,每个元素都有编号;而在映射中,每个元素都有名称(也叫键)
- 有一种既不是序列也不是映射的容器,叫做集合(set)
有几种操作适用于序列:
- 索引
- 切片
- 相加
- 相乘
- 成员资格检查
- python内置函数确定序列的长度及找出序列中最大元素和最小元素
- 迭代
索引
字符串就是有字符组成的索引,索引0指向第一个元素。不同于其他一些语言,Python没有专门用于表示字符的类型,因此一个字符就是只包含一个元素的字符串。
对于字符串字面量(以及其他的序列字面量), 可以直接对索引进行操作,无需将其赋值给变量。
序列中的所有元素都有编号,从0开始递增,依次下去,称为索引(index)。可以通过索引来获取元素,这种方式适用于所有的序列。
负数索引将从右(即最后一个元素)开始往左数,因此-1是最后一个元素。
如果调用函数返回一个序列,可以直接对其执行索引操作
>>> fourth = input('Year: ')[3]
Year: 2022
>>> fourth
'2'
>>>
>>> greenting = 'Hello'
>>> greenting[0]
'H'
>>> greenting[1]
'e'
>>>
>>> 'Hello'[-2]
'l'
>>>
eg.输入年、月(数1-12)、日(数1-31),再使用相应的月份名称将日期打印出来
# 将以数指定年、月、日的日期打印出来
months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'Auguest',
'September',
'October',
'November',
'December'
]
# 一个列表,其中包含数 1-31 对应的结尾
endings = ['st', 'nd', 'rd'] + 17 * ['th'] + ['st', 'nd', 'rd'] + 7 * ['th'] + ['st']
'''
分日英语:
日 全称 缩写
1日 first 1st
2日 second 2nd
3日 third 3rd
4日 fourth 4th
5日 fifth 5th
6日 sixth 6th
7日 seventh 7th
8日 eighth 8th
9日 ninth 9th
10日 tenth 10th
11日 eleventh 11th
12日 twelfth 12th
13日 thirteenth 13th
14日 fourteenth 14th
15日 fifteenth 15th
16日 sixteenth 16th
17日 seventeenth 17th
18日 eighteenth 18th
19日 nineteenth 19th
20日 twentieth 20th
21日 twenty-first 21st
22日 twenty-second 22nd
23日 twenty-third 23rd
24日 twenty-fourth 24th
25日 twenty-fifth 25th
26日 twenty-sixth 26th
27日 twenty-seventh 27th
28日 twenty-eighth 28th
29日 twenty-ninth 29th
30日 thirtieth 30th
31日 thirty-first 31st
'''
year = input('Year: ')
month = input('Month(1-12): ')
day = input('Day(1-31): ')
month_number = int(month)
day_number = int(day)
# 别忘了将表示月和日的数减1,这样才能得到正确的索引
month_name = months[month_number-1]
ordinal = day + endings[day_number-1]
print(month_name + ' ' + ordinal + ' ' + year)
# output
Year: 2022
Month(1-12): 11
Day(1-31): 14
November 14td 2022
切片
除使用索引来访问单个元素外,还可以使用切片(slicing)来访问特定范围内的元元素。使用两个索引,并用冒号分隔.
切片适用于提取序列的一部分,其中的编号非常重要:第一个索引是包含第一个元素的编号,但第二个索引是切片后余下的第一个元素的编号。
简言之,切片中提供的两个索引来确定边界,包含第一个索引的元素,不包含第二个索引的元素。
>>>
>>> tag = '<a href="http://www.python.org">Python web site</a>'
>>> tag[9:30]
'http://www.python.org'
>>> tag[32:-4]
'Python web site'
>>>
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> numbers[3:6]
[4, 5, 6]
>>> numbers[0:1]
[1]
>>>
访问数字列表的最后三个元素:
>>>
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> numbers[7:10] # 索引为10代表第11个元素,上述列表并不存在,所以取得是7~10个元素
[8, 9, 10]
>>> numbers[-3:-1] # 注意-1代表最后一个元素,但是取不到
[8, 9]
>>> numbers[-3:0] # 因为索引-3代表的元素在索引0代表的元素后面,所以这个结果是一个空序列
[]
>>> numbers[-3:] # 如果切片结束于序列末尾,可以省略第二个索引
[8, 9, 10]
>>> numbers[:3] # 同样,如果切片开始于序列,可以省略第一个索引
[1, 2, 3]
>>> numbers[:] # 所以,复制整个序列,可以省略两个索引
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>>
切片时,我们通常默认步长为1且省略,如果需要指定步长的话,可以在切片的方括号中指定第三个参数:步长
>>>
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> numbers[0:10:2] # 第三个参数为步长2,即每2个元素取一个元素
[1, 3, 5, 7, 9]
>>> numbers[3:6:3] # 可以理解为numbers[3:6]=[4, 5, 6]从开始每隔3个元素取一个组成新的列表
[4]
>>> numbers[::3] # 省略开始和结束切片,步长为3
[1, 4, 7, 10]
>>> numbers[0:10:0] # 步长为0无法移动,所以会报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: slice step cannot be zero
>>> numbers[8:3:-1] # 负数步长表示从序列右边开始切片,注意此时的开始索引和结束索引也需要倒置
[9, 8, 7, 6, 5]
>>> numbers[10:0:-3]
[10, 7, 4]
>>> numbers[0:10:-2] # 步长为负数时,第一个索引必须比第二个索引大,否则切片为空
[]
>>> numbers[::-2]
[10, 8, 6, 4, 2]
>>> numbers[5::-2] # 步长为正数,从起点移动到终点;步长为负数,从终点移动到起点
[6, 4, 2]
>>> numbers[:5:-2]
[10, 8]
>>>
序列相加
可以使用加法运算来拼接序列。
注意,不能拼接列表和字符串,虽然它们都是序列。一般而言,不能拼接不同类型的序列。
>>> [1, 2, 3] + [4, 5, 6]
[1, 2, 3, 4, 5, 6]
>>>
>>> 'Hello, ' + 'world!'
'Hello, world!'
>>>
>>> [1, 2, 3] + 'world!'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list
>>> 'Hello, ' + [4, 5, 6]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "list") to str
>>>
乘法
将序列与数相乘时,将重复这个序列来创建一个新的序列。
>>>
>>> 'python ' * 5
'python python python python python '
>>>
>>> [42] * 10
[42, 42, 42, 42, 42, 42, 42, 42, 42, 42]
>>> [None] * 10 # 在Python中[0]表示一个元素为0的列表,什么都没有用None表示,所以空列表表示为[None],因此初始化一个什么都没有的空列表应该用[None]而不是[0]
[None, None, None, None, None, None, None, None, None, None]
>>>
成员资格
要检查特定的值是否包含在序列中,可使用运算符in,不同于算术运算符,in满足条件返回True,不满足条件返回False,这样的运算符称为布尔运算符。True和False称为布尔值。
>>>
>>> permissions = 'rw'
>>> 'w' in permissions # 检查文件的写入情况等
True
>>> 'x' in permissions
False
>>>
>>> users = ['mlh', 'foo', 'bar']
>>> input('Enter your user name: ') in users # 程序需要执行特定的安全策略时很有用
Enter your user name: mlh
True
>>> subjects = '$$$ Get rich now!!! $$$' # 过滤垃圾邮件
>>> '$$$' in subjects
True
>>>
检查用户名和PIN码
# 检查用户名和PIN码
database = [
['albert', '1234'],
['dilbert', '4242'],
['smith', '7524'],
['jones', '9843']
]
username = input('User name: ')
pin = input('PIN code: ')
if [username, pin] in database:
print('Access granted')
# Output
User name: smith
PIN code: 7524
Access granted
长度、最小值、最大值
Python内置函数len()、min()、max()分别表示返回序列包含的元素个数、返回序列中的最大元素、返回序列中的最小元素。
>>>
>>> numbers = [100, 56, 39]
>>> len(numbers)
3
>>> max(numbers)
100
>>> min(numbers)
39
>>> max(1,4,6)
6
>>> min(6, 4, 76, 3)
3
>>>