Python序列、列表及其方法

在上一节里面我们讲到了变量。但是,生活中也并不是哪里的数据都适合使用变量来存储。比如,一些成堆出现的数据。那么,本节就要引入一个新的概念:数据结构

所谓数据结构,实际上就是通过某种方式(比如给元素编号),组织在一起的数据集合。在Python中,最基本的数据结构就是序列(sequence)。序列中的每一个元素都被分配一个序号,也就是元素的位置,称之为索引。但是,Python的索引是从0开始,而不是我们习惯的从1开始。

Python包括6中内建序列:列表(list),元组(tuple),字符串(string),Unicode字符串(Unicode string),buffer对象和xrange对象。本节只讨论列表元组

另外,序列中的元素也可以是一个序列,如:

>>> edward = ['Edward Gumby', 42]
>>> john = ['John Smith', 50]
>>> database = [edward, john]
>>> database
[['Edward Gumby', 42], ['John Smith', 50]]

通用序列操作

所有下序列类型都可以进行某些特定的操作。包括索引(indexing)分片(slicing)加(adding)乘(multiplying)成员资格以及迭代(iteration,本节不讲)。除此之外,Python还有计算序列长度,找出最大最小元素等内建函数。

索引

通过元素的编号来访问元素(从0开始,谨记!):

>>> name = 'TechZone'
>>> name[0]
'T'
>>> name[5]
'o'

由于是从0开始,于是索引0对应的就是第一个元素,索引6就是第五个元素。

当然,如果你不希望把这个序列赋值给一个变量,也可以直接进行操作:

>>> 'TechZone'[5]
'o'

亦或许,你想把序列中某一个元素赋值给一个变量,也是可以的:

>>> letter = 'TechZone'[5]
>>> letter
'o'

如果这个序列很长,也可以倒着数:

>>> 'Hello'[-1] #代表从结尾开始数的第一个
'o'

分片

和索引一样,分片是用来访问一段元素的。比如我想一次性访问序列的第3到第6个元素:

>>> name = 'TechZone'
>>> name[2:6]
'chZo'

需要注意的是,起始元素(冒号左边)是包含在内的,而终止元素(冒号右边)是不包含在内的。因此name[2:6]实际上等价于name[2] + name[3] + name[4] + name[5]

如果我们要访问最后的三个元素怎么办呢?

当然可以使用常规的方法:

>>> name[5:8]
'one'

如果我们要从结尾开始访问呢?

>>> name[-3:-1]
'on'

由于终止元素不包含在分片里面,于是后面我们就访问不到。

改改试试:

>>> name[-3:0]
''

什么都没有返回!为什么会这样呢?

因为[0]其实比[-3]更先出现。那么起始元素比终止元素还大,从数学的角度来说,就是空集了。

难道真的没有办法这样访问吗?

并不是,看看这样:

>>> name[-3:]
'one'

把终止元素的位置留空,那么Python就会自动认为你要一直访问到最后元素,于是就把这个问题巧妙解决了。

当然,这个方法也可以这么用:

>>> name[:3]
'Tec'
>>> name[:]
'TechZone'

很好理解吧。

分片的步长

其实分片还有一个参数,我们刚刚并没有用,就是步长。步长的默认设置为1,意思就是挨个访问。比如:

>>> name[1:4]
'ech'

实际上等价于:

>>> name[1:4:1]
'ech'

如果步长改成2:

>>> name[1:4:2]
'eh'

你会发现检索的单位变成了2(也就是说,中间会跳过一个元素)

也许这么看,就好理解了:

>>> nums = [1,2,3,4,5,6,7,8,9,10]
>>> nums[::1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> nums[::2]
[1, 3, 5, 7, 9]
>>> nums[::3]
[1, 4, 7, 10]
>>> nums[::4]
[1, 5, 9]

当然,步长不能够为0,但是可以为负数(倒过来检索):

>>> nums[::-1]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> nums[::-2]
[10, 8, 6, 4, 2]
>>> nums[::-3]
[10, 7, 4, 1]
>>> nums[::-4]
[10, 6, 2]

序列运算

相加

>>> [1,2,3]+[4,5,6]
[1, 2, 3, 4, 5, 6]
>>> 'TechZone'+'Harris'
'TechZoneHarris'
>>> [1,2,3]+'Harris'
'''
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    [1,2,3]+'Harris'
TypeError: can only concatenate list (not "str") to list
'''

相同类型的序列相加,实际上就是拼接起来。但是不同类型的序列是不能够相加的。

乘法

>>> 'Harris' * 5
'HarrisHarrisHarrisHarrisHarris'
>>> [1,2] * 10
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]

也很好理解。

初始化

如果我想创建一个列表,作为占位符(暂时不用,但是以后要用的),那么可以用一对方括号[]来表示。如果想创建一个拥有10个元素的列表占位符,那么该怎么办呢?

我们可以使用一些对于你来说没有意义的字符,比如0:

>>> space = [0] * 10
>>> space
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

不过这样的作法其实并不是十分稳妥,因为没准你找不出来这样的特殊的数字。那么这里介绍一个Python内建值:None,表示什么都没有。那么我们的占位符就可以这样创建:

>>> space = [None] * 10
>>> space
[None, None, None, None, None, None, None, None, None, None]

成员资格

判断一个值是否在序列中,我们可以使用in运算符。这种运算符不同于加减乘除,它会去检查我们的条件是否为真,若是,则返回True,反之则返回False。这样的运算符我们叫做布尔运算符,返回的这个值称之为布尔值

>>> user = ['Harris', 'Mary','Scott']
>>> 'Harris' in user
True
>>> 'Jack' in user
False

长度、最值

>>> name = 'HarrisWilde'
>>> len(name) #序列长度
11
>>> len([1,2,3,4])
4
>>> max([1,3,2,13,6,5,8]) #最大值
13
>>> min([0.01, 0.02, 0.009, 0.015]) #最小值
0.009

列表

使用[]括起来的序列集合就是列表。

list函数

使用list函数来将序列转换为列表。

>>> list("TechZone")
['T', 'e', 'c', 'h', 'Z', 'o', 'n', 'e']

你还可以使用join函数来把序列中所有的元素(的字符串表示)合并为一个新的字符串:

>>> seq = list("TechZone")
>>> '-'.join(seq)
'T-e-c-h-Z-o-n-e'

基本列表操作

元素赋值

为单个元素赋值:

>>> x = [0] * 3
>>> x[1] = 1
>>> x
[0, 1, 0]

删除元素

使用del函数:

>>> x
[0, 1, 0]
>>> del x[2]
>>> x
[0, 1]

分片赋值

分片赋值可以实现一次性的批量赋值:

>>> x = list("python")
>>> x
['p', 'y', 't', 'h', 'o', 'n']
>>> x[4:] = '12'
>>> x
['p', 'y', 't', 'h', '1', '2']

而且还可以非等长替换:

>>> x
['p', 'y', 't', 'h', '1', '2']
>>> x[4:] = 'Lang'
>>> x
['p', 'y', 't', 'h', 'L', 'a', 'n', 'g']

因此,也可以间接地增加或删除元素:

>>> x[8:8] = '12' #在最后的不存在的位置增加
>>> x
['p', 'y', 't', 'h', 'L', 'a', 'n', 'g', '1', '2']
>>> x[4:8] = []
>>> x
['p', 'y', 't', 'h', '1', '2']

列表方法

append

此方法用于在列表后面追加元素:

>>> nums = [1,2,3]
>>> nums.append(4)
>>> nums
[1, 2, 3, 4]

count

此方法统计某个元素在列表中出现的次数:

>>> name = 'TechZone'
>>> name.count('e')
2

extend

此方法可以在末尾一次性追加多个值,并且更改原来的列表:

>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a.extend(b)
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[4, 5, 6]

index

此方法用于找出列表中某个值的第一个匹配元素的索引,若找不到则会返回错误:

>>> name = 'TechZone'
>>> name.index('e')
1
>>> name.index('a')
'''
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    name.index('a')
ValueError: substring not found
'''

insert

此方法用于将对象插入到列表中:

>>> nums = [1,2,3,5]
>>> nums.insert(3, 'four')
>>> nums
[1, 2, 3, 'four', 5]

pop

此方法用于移除列表中的最后一个元素,并且返回被移除元素的值:

>>> nums = [1,2,3,4]
>>> nums.pop()
4
>>> nums
[1, 2, 3]

pop方法是唯一一个既能修改列表又能返回元素值(除了None)的列表方法

remove

remove方法用于移除列表中的某个值的首个匹配项:

>>> words = ['a','friend','in','need','is','a','friend','indeed']
>>> words.remove('friend')
>>> words
['a', 'in', 'need', 'is', 'a', 'friend', 'indeed']

remove是一个没有返回值的原位置改变方法。和pop恰恰相反。

reverse

此方法将列表中的元素反向存放。

>>> x = [1,2,3]
>>> x.reverse()
>>> x
[3, 2, 1]

此方法也是不返回值,和remove一样。

如果需要对一个序列进行反向迭代,那么可以使用reversed函数。这个函数返回的是迭代器对象(iterator)。当然,使用list函数把返回的对象转换成列表也是可行的:

>>> x = [1,2,3]
>>> list(reversed(x))
[3, 2, 1]

sort

此方法用于对列表进行原地排序。所谓原地排序,就是更改原来的列表,而不是返回一个已排序的副本。

>>> x = [4,5,3,6,2,5,1]
>>> x.sort()
>>> x
[1, 2, 3, 4, 5, 5, 6]

如果你想得到的恰恰是一个副本,想保留原来的列表,千万不要这么做:

>>> x = [4,5,3,6,2,5,1]
>>> y = x.sort() #错误的做法
>>> print(y)
None

因为sort函数是不返回值的(实际上返回的是空值)。如果要实现这个功能,那么只能把原先x的副本赋给y,然后对y进行排序:

>>> x = [4,5,3,6,2,5,1]
>>> y = x
>>> y.sort()
>>> y
[1, 2, 3, 4, 5, 5, 6]
>>> x
[1, 2, 3, 4, 5, 5, 6]

你会发现,为何原来的x也被改变了呢?

原来,简单的等号赋值,会让x和y指向同一个对象。那么,我们使用分片的方法来赋值,就可以巧妙地躲开这个问题:

>>> x = [4,5,3,6,2,5,1]
>>> y = x[:]
>>> y.sort()
>>> y
[1, 2, 3, 4, 5, 5, 6]
>>> x
[4, 5, 3, 6, 2, 5, 1]

另外,还可以使用sorted函数来获取已排序副本:

>>> x = [4,5,3,6,2,5,1]
>>> y = sorted(x)
>>> y
[1, 2, 3, 4, 5, 5, 6]
>>> x
[4, 5, 3, 6, 2, 5, 1]

sorted函数可以用于任何序列,但是总会返回一个列表:

>>> sorted("TechZone")
['T', 'Z', 'c', 'e', 'e', 'h', 'n', 'o']

此函数默认是升序排序,如果我想降序,怎么办呢?

可以先排好序之后再反转,不过,有个更简便的方法:使用reverse参数。

>>> x = [4,5,3,6,2,5,1]
>>> x.sort(reverse = False) #默认情况,就是不写参数的情况
>>> x
[1, 2, 3, 4, 5, 5, 6]
>>> x.sort(reverse = True) #应用reverse参数
>>> x
[6, 5, 5, 4, 3, 2, 1]

当然,此函数还可以进行更高级的排序,就是使用key参数。所谓key,笔者认为就是排序参考关键词。默认是按照值的大小(若是字符串则比较其对应编码的大小),使用此参数,就可以实现别的参考值。

比如我想根据字符串长度来排序:

>>> string = ['TechZone','HarrisWIlde','Python','Programing']
>>> string.sort(key=len)
>>> string
['Python', 'TechZone', 'Programing', 'HarrisWIlde']

当然,两个参数也可以一起用:

>>> string = ['TechZone','HarrisWIlde','Python','Programing']
>>> string.sort(key=len, reverse=True)
>>> string
['HarrisWIlde', 'Programing', 'TechZone', 'Python']

这两个参数对于sorted()都有效。