Cao Yi

Python 集合类型

Index

Python 的集合类型主要有 list, tuple, dictset, 其中 dict 相当于 Java 中的 Map.

list, tupleset 都是列表类型,简单的区分是:

1. list

中文一般译作列表

1.1 定义

可以定义一个空的列表 L = [],也可以在定义时赋值 L = [1, '2', 'hello']。注意这里使用了中括号。

>>> L = []
>>> L
[]
>>> L = [1, '2', 'hello']
>>> L
[1, '2', 'hello']

上面的代码中,L 被定义了两次,新的定义会覆盖旧的。

还可以使用生成式定义:

>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> [x * x * x for x in range(1, 11)]
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> [x * x * x for x in range(1, 11) if x % 3 == 0] 
[27, 216, 729]
>>> [(x,  x * x * x) for x in range(1, 11) if x % 3 == 0] 
[(3, 27), (6, 216), (9, 729)]

生成式可以多层循环,参用Python的列表生成式批量产生姓名

1.2 长度

list 的长度即所含元素的个数,可以通过 len() 求得。

(接前面的代码)

>>> len(L)
3

1.3 访问元素

list 中的元素可以根据其索引访问,从0开始。它还支持负整数索引,表示倒数第几个数。索引超出范围会引发报错信息。

(接前面的代码)

>>> L[0]
1
>>> L[-1]
'hello'
>>> L[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> L[-4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

[1, '2', 'hello'] 中元素有3个,索引值从左往右是 0, 1, 2, 从右往左是 -1, -2, -3,任何不在这两个范围内的索引值都会引起越界错误,比如 L[5]L[-4]

1.4 添加元素

添加元素有两种方式,一种可以通过 append 方法在尾部添加元素。

(接前面的代码)

>>> L.append('world')
>>> L
[1, '2', 'hello', 'world']

还有一种方式是通过 insert() 在某个索引位置添加,新的元素添加后,位于新元素右侧的所有元素都往后移动一位。

>>> L.insert(2, 'hi')
>>> L
[1, '2', 'hi', 'hello', 'world']
>>> L.insert(-2, 'word')
>>> L
[1, '2', 'hi', 'word', 'hello', 'world']

1.5 删除元素

删除元素也有两种方式,一种是通过pop()删除列表尾部的元素,另一种是通过pop(index)删除指定 index 的元素,下面举例说明。

>>> L.pop()
'world'
>>> L
[1, '2', 'hi', 'word', 'hello']
>>> L.pop(1)
'2'
>>> L
[1, 'hi', 'word', 'hello']
>>> L.pop(-1)
'hello'
>>> L
[1, 'hi', 'word']

1.6 多维列表

当元素本身也是list时,就构成了多维列表。

1.7 切片

切片用于取数列中中某一部分,比用循环方便一些。 这部分的例子主要来自廖雪峰的教程

取数列中最开始的几个元素,起始的index值如果是0可以省略,索引值从0开始。

>>> L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
>>> L
['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
>>> L[0:3]
['Michael', 'Sarah', 'Tracy']
>>> L[:3]

取从m到n(不包含)的(n-m)个元素,负值作index也可以。

['Michael', 'Sarah', 'Tracy']
>>> L[1:3]
['Sarah', 'Tracy']
>>> L[-2:]
['Bob', 'Jack']
>>> L[-2:-1]
['Bob']

高级切片操作。分组取其一,示例:

定义一个数组。

>>> L = list(range(100))
>>> L
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

每五个取一个。相当于五个一组,取每组第一个元素。

>>> L[::5]
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
>>> L[:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

在前10个元素里,每两个取一个。

>>> L[:10:2]
[0, 2, 4, 6, 8]

反向切片的内容参Python 切片操作中 step 为负值如何理解?

2. tuple

tuple 一般译作元组,它是一个固定列表,一旦定义即确定,并不可修改。因此它的元素只能被访问,但不能增删改,它可以通过元素的索引值访问。

2.1 定义

可以定义一个空的 t = (),也可以在定义是赋值 t = (1, '2', 'hello')。注意这里使用了圆括号,前面定义列表时使用的是中括号。

>>> t
()
>>> t = (1, '2', 'hello')
>>> t
(1, '2', 'hello')

因为圆括号有时只是为了显著地标识某些代码而不具有实际意义,所以当元组的元素只有一个时,就会引起歧义。如何定义只有一个元素的元组呢?答案是加一个逗号。

t = (1) # defines a number
t = (1,) # defines a tuple, the comma is a must.

上面代码片段里,第一句仅仅是定义了一个数,第二个才是定义元组,注意那个唯一的元素右下角的逗号。单元素的元组定义,确实比较丑。

2.2 访问元素

访问元组(tuple)的方式和访问列表(list)没有区别。越界也会报错。

>>> t = (1, '2', 'hello')
>>> t[1]
'2'
>>> t[-1]
'hello'
>>> t[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: tuple index out of range

2.3 元组的元素是否可修改

元组的元素不可修改指的是一个元组包含哪些元素是确定的,但如果元素本身是可修改的对象,则这个对象是可以修改的。

2.3 切片

tuple 也可以应用切片操作,比如

>>> (0, 1, 2, 3, 4, 5, 6)[:3]
(0, 1, 2)

3. set

set 就是数学意义上的集合,无序,无重复元素的集合。

3.1 创建 set

一般通过 list 来创建 set

>>> s = set([1, 2, 3, 4, 4, 5, 6])
>>> s
{1, 2, 3, 4, 5, 6}

还可以通过花括号直接创建:

>>> s = {1, 2, 3, 4, 4, 5, 6}    
>>> s
{1, 2, 3, 4, 5, 6}

到这里,集齐了 Python 集合操作对括号的使用:

3.2 增删元素

可以通过 addremove 来增删 set 中的元素。

>>> s.add(7)
>>> s
{1, 2, 3, 4, 5, 6, 7}
>>> s.remove(4)
>>> s
{1, 2, 3, 5, 6, 7}

3.3 检查是否包含某个元素

可以使用关键字 in 来判断集合中是否包含某个元素。

>>> if 3 in s:
...   print('Yes')
...
Yes
>>> if 8 in s:
...   print('Yes')
... else:
...   print('No')
...
No

4. 词典(Dictionary)

词典(Dictionary)结构在Java中也叫 Map,在Python中用关键 dict 表示。它一个键值对 key-value 的集合。

4.1 创建 dict

也是用大括号创建:

>>> d = {'alice': 0.1, 'bob': 0.2}
>>> d
{'alice': 0.1, 'bob': 0.2}

注意,要创建一个空白的词典,用 {},而要创建一个空白的 setset():

>>> s = set()
>>> type(s)
<class 'set'>
>>> d = {}
>>> type(d)
<class 'dict'>

4.2 增删改查

可以通过 key 直接访问,如果 key 不存在则报错。

>>> d['bob']
0.2
>>> d['dell'] 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'dell'

可以通过赋值的方式给 dict 更新或新增元素。dict的key必须是不可变对象。

>>> d['alice'] = 0.11 
>>> d
{'alice': 0.11, 'bob': 0.2}
>>> d['charles'] = 0.3
>>> d
{'alice': 0.11, 'bob': 0.2, 'charles': 0.3}

可以通过 del 删除元素

>>> d
{'alice': 0.11, 'bob': 0.2, 'charles': 0.3}
>>> del d['alice']
>>> d
{'bob': 0.2, 'charles': 0.3}

4.3 list VS dict

和list比较,dict有以下几个特点:

  1. 查找和插入的速度极快,不会随着key的增加而变慢;
  2. 需要占用大量的内存,内存浪费多。

而list相反:

  1. 查找和插入的时间随着元素的增加而增加;
  2. 占用空间小,浪费内存很少。

5. range

可以通过 range 去创建 list, set, tuple 对象:

>>> type(range(1,20))
<class 'range'>
>>> a = range(1,20)
>>> a
range(1, 20)
>>> a = list(range(1,20))
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> a = set(range(1,20))
>>> a
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
>>> a = tuple(range(1,20))
>>> a
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)

range 对象也是可以遍历的,如:

>>> L = range(20)
>>> L
range(0, 20)
>>> for i in L:    
...     print(i)
... 
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> type(L)
<class 'range'>

参考: