title: 数据结构 create: 2016.12.7 modified: 2016.12.7 tags: python 列表 元组 字符串 字典

  2

[TOC]

数据结构是通过某种方式(例如对元素进行编号)组织在一起的数据元素的集合。在Python中,最基本的数据结构是序列(sequence)。序列中每个元素被分配一个序号-即元素的位置,也称为索引。第一个索引是0。Python中包含6种内建的序列,最常用的类型是:列表、元组和字符串。列表和元组/字符串的主要区别在于,列表可以修改,元组/字符串则不能。一般来说,在几乎所有的情况下列表都可以替代元组。

1 通用序列操作

所有序列类型都可以进行某些特定的操作,包括:索引(indexing)、分片(sliceing)、加(adding)、乘(multiplying)以及检查某个元素是否属于序列的成员。除此之外,Python还有计算序列长度、找出最大元素和最小元素的内建函数。

1.1 索引

序列中所有元素都有编号(索引)-从0开始递增。这些元素可以通过索引进行访问,如下:


In [1]:
greet='hello'
greet[0]


Out[1]:
'h'

In [2]:
greet[-1]


Out[2]:
'o'

使用负数索引时,Python会从右边,也就是从最后1个元素开始计数。最后1个元素的位置编号是-1。

1.2 分片

使用分片操作来访问一定范围内的元素。分片可通过冒号相隔两个索引来实现,如下:


In [6]:
greet='hello, world!'
greet[1:8]


Out[6]:
'ello, w'

In [9]:
nunbers=[1,2,3,4,5,6,7,8]
nunbers[3:6]


Out[9]:
[4, 5, 6]

In [10]:
nunbers[-3:-1]


Out[10]:
[6, 7]

In [11]:
nunbers[-3:]


Out[11]:
[6, 7, 8]

分片操作的实现需要提供两个索引作为边界,第1个索引的元素是包含在分片内的,而第2个则不包含在分片内。


In [12]:
nunbers[0:6:2]


Out[12]:
[1, 3, 5]

在这个例子中,分片包含了另外一个数字,这就是步长的显示设置。步长为2的分片包括的是从开始到结束每隔1个的元素。步长可以是负数,从右到左提取元素:


In [14]:
nunbers[7:3:-2]


Out[14]:
[8, 6]

1.3 序列相加

使用加号可以进行序列的连接操作:


In [15]:
[1,2,3]+[4,5,6]


Out[15]:
[1, 2, 3, 4, 5, 6]

In [16]:
'hello, '+'world!'


Out[16]:
'hello, world!'

1.4 乘法

用数字x乘以一个序列会生成新的序列,而在新序列中,原来的序列被重复x次:


In [17]:
'python'*5


Out[17]:
'pythonpythonpythonpythonpython'

In [18]:
[12]*3


Out[18]:
[12, 12, 12]

In [19]:
[None]*10


Out[19]:
[None, None, None, None, None, None, None, None, None, None]

有时候可能会需要一个值来代表空值,这个时候就需要使用None。None是一个Python的内建值,它确切含义是“这里什么也没有”。

1.5 成员资格

为了检测一个值是否在序列中,可以使用in运算符(布尔运算符)。


In [20]:
'a' in 'hello'


Out[20]:
False

In [21]:
'e' in 'hello'


Out[21]:
True

1.6 长度、最小值和最大值

内建函数len、min和max很有用。


In [22]:
numbers=[1,2,3]
len(numbers)


Out[22]:
3

In [23]:
max(numbers)


Out[23]:
3

2 列表

接下来讨论列表不同于元组和字符串的地方:列表是可变的-可以改变列表的内容,并且列表有很多有用的、专门的方法。

2.1 list函数

因为字符串不能像列表一样被修改,所以有时根据字符串创建列表会很有用。list函数可以实现这个操作。


In [24]:
list('hello')


Out[24]:
['h', 'e', 'l', 'l', 'o']

可以用下面的表达式将一个由字符组成的列表转换为字符串:


In [28]:
''.join(['h', 'e', 'l', 'l', 'o'])


Out[28]:
'hello'

2.2 基本的列表操作

列表可以使用所有适用于序列的标准操作,如索引、分片和连接等。接下来会介绍一些可以改变列表的方法。

改变列表:元素赋值
使用索引标记来为某个特定的、位置明确的元素赋值,如下:


In [31]:
x=[1,1,1]
x[1]=2
x


Out[31]:
[1, 2, 1]

删除元素
使用del语句来实现


In [32]:
del x[1]
x


Out[32]:
[1, 1]

分片赋值

分片是一个非常强大的特性,分片赋值操作则更加显示它的强大。


In [33]:
name=list('Perl')
name


Out[33]:
['P', 'e', 'r', 'l']

In [35]:
name[2:]=list('ar')
name


Out[35]:
['P', 'e', 'a', 'r']

2.3 列表方法

方法是一个与某些对象有紧密联系的函数。对象可能是列表、数字,也可能是字符串或者其他类型的对象。方法可以这样进行调用:
对象.方法(参数)

除了对象被放置到方法名之前,并且两者之间用一个点号隔开,方法调用与函数调用很类似。列表提供了几个方法,用于检查或者修改其中的内容。

1. append
append方法用于在列表末尾追加新的对象:


In [37]:
lst=[1,2,3]
lst.append(2)
lst


Out[37]:
[1, 2, 3, 2]

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


In [38]:
lst.count(2)


Out[38]:
2

3. extend
extend方法可以在列表的末尾一次性追加另一个序列中的多个值。


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


Out[39]:
[1, 2, 3, 4, 5, 6]

4. index
index方法用于从列表中找出某个值第一个匹配项的索引位置:


In [41]:
knights=['we','are','the','knights']
knights.index('are')


Out[41]:
1

5. insert
insert方法用于将对象插入到列表中:


In [42]:
a=[1,2,4]
a.insert(2,'three')
a


Out[42]:
[1, 2, 'three', 4]

6. pop
pop方法会移除列表中的一个元素(默认是最后一个),并且返回该元素的值 :


In [43]:
a.pop()


Out[43]:
4

In [44]:
a


Out[44]:
[1, 2, 'three']

In [45]:
a.pop(1)


Out[45]:
2

In [46]:
a


Out[46]:
[1, 'three']

使用pop方法可以实现一种常见的数据结构—栈。栈的原理就像堆放盘子那样,只能在顶部放一个盘子。同样,也只能从顶部拿走一个盘子。对于上述两个栈操作(放入和移除)-入栈(push)和出栈(pop)。Python没有入栈方法,但可以用append方法替代。


In [47]:
x=[1,2,3]
x.append(x.pop())
x


Out[47]:
[1, 2, 3]

7. remove
remove方法会移除列表中某个值的第一个匹配项 :


In [48]:
x.remove(2)
x


Out[48]:
[1, 3]

remove是一个没有返回值的原位置改变方法,这与pop方法不同。

8. reverse
reverse方法会将列表中的元素反向存放 :


In [49]:
x.reverse()
x


Out[49]:
[3, 1]

9. sort
sort方法会将列表中的元素进行排序 :


In [50]:
y=[4,2,3,1]
y.sort()
y


Out[50]:
[1, 2, 3, 4]

另一种获取已排序的列表副本的方法是,使用sorted函数:


In [51]:
x=[4,2,3,1]
y=sorted(x)
x


Out[51]:
[4, 2, 3, 1]

In [52]:
y


Out[52]:
[1, 2, 3, 4]

In [59]:
y.reverse()
y


Out[59]:
[4, 3, 2, 1]

3 元组:不可变序列

可以用逗号分隔一些值,自动创建元组:


In [60]:
1,2,3


Out[60]:
(1, 2, 3)

元组也能通过圆括号括起来:


In [61]:
(1,2,3)


Out[61]:
(1, 2, 3)

3.1 tuple函数

以一个序列为参数并把它转换为元组:


In [62]:
tuple([1,2,3])


Out[62]:
(1, 2, 3)

In [63]:
tuple('abc')


Out[63]:
('a', 'b', 'c')

3.2 基本元组操作

除了创建元组和访问元组元素之外,也没有太多其他操作:


In [68]:
x=1,2,3
x[1:3]


Out[68]:
(2, 3)

4 字符串

4.1 字符串格式化

字符串格式化使用字符串格式化操作符,即百分号%来实现。在%的左侧放置一个字符串(格式化字符串),而右侧则放置希望格式化的值。可以使用一个值,比如一个字符串或数字,也可以使用多个值的元组或字典。一般情况下使用元组:


In [70]:
format='hello, %s. %s enough for ya?'
values=('world','Hot')
print format % values


hello, world. Hot enough for ya?

格式化字符串%s部分称为转换说明符,它们标记了需要插入转换值的位置。s表示值会被格式化为字符串-如果不是字符串,则会用str将其转换为字符串。
如果要格式化实数(浮点数),可以使用f说明符类型,同时提供所需要的精度:一个句点再加上希望保留的小数位数。


In [72]:
format='Pi with four decimals:%.4f'
from math import pi
print format % pi


Pi with four decimals:3.1416

In [74]:
'Pi :%10f' % pi   #字段宽 10


Out[74]:
'Pi :  3.141593'

In [75]:
'Pi :%010.2f' % pi #用0进行空位填充


Out[75]:
'Pi :0000003.14'

In [76]:
'%-10.2f' % pi   #减号用来左对齐数值


Out[76]:
'3.14      '

加号表示不管是正数还是负数都标示出符号(同样是在对齐时很有用):


In [77]:
print ('%+5d' % 10)+'\n'+('%+5d' % -10)


  +10
  -10

4.2 字符串方法

字符串的方法很多,这是因为字符串从string模块中“继承”了很多方法。
1. find
find方法可以在一个较长的字符串中查找子字符串。它返回子串所在位置的最左端索引。如果没有找到则返回-1。


In [78]:
'hello, world!'.find('wor')


Out[78]:
7

2. join
join方法是非常重要的字符串方法,它是split方法的逆方法。


In [79]:
seq=[1,2,3]
'+'.join(seq)  #连接数字列表


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-79-057454ab231d> in <module>()
      1 seq=[1,2,3]
----> 2 '+'.join(seq)  #连接数字列表

TypeError: sequence item 0: expected string, int found

In [80]:
seq=['1','2','3']
'+'.join(seq)  #连接字符串列表


Out[80]:
'1+2+3'

可以看到,需要添加的队列元素都必须是字符串。

3. lower
lower方法返回字符串的小写字母版。


In [81]:
'Hello, World!'.lower()


Out[81]:
'hello, world!'

4. replace
replace方法返回某字符串的所有匹配项均被替换之后得到字符串。


In [82]:
'This is a shoe'.replace('s','aaa')


Out[82]:
'Thiaaa iaaa a aaahoe'

5. split
split方法是join的逆方法,用来将字符串分割成序列。如果不提供任何分隔符,程序会把所有空格作为分隔符(空格、制表、换行等)。


In [83]:
'1+2+3'.split('+')


Out[83]:
['1', '2', '3']

6. strip
strip方法返回去除两侧(不包括内部)空格的字符串:


In [84]:
'      hello world       '.strip()


Out[84]:
'hello world'

5 字典

字典是一种通过名字(键)引用值的数据结构。这种结构类型称为映射(mapping)。

5.1 创建和使用字典

字典可以通过下面的方式创建:


In [1]:
phonebook={'Alice':'2341','Beth':9102}
phonebook


Out[1]:
{'Alice': '2341', 'Beth': 9102}

5.2 dict函数

可以用dict函数,通过其他映射(比如其他字典)或者(键,值)这样的序列对建立字典。


In [2]:
items=[('name','Gumby'),('age','42')]
d=dict(items)
d


Out[2]:
{'age': '42', 'name': 'Gumby'}

dict函数也可以通过关键字参数来创建字典,如下:


In [3]:
d=dict(name='Gumby',age=42)
d


Out[3]:
{'age': 42, 'name': 'Gumby'}

5.3 基本字典操作

字典的基本行为在很多方面与序列类似:
len(d)返回d中项(键-值对)的数量;
d[k]返回关联到键k上的值;
d[k]=v将值v关联到键k上;
del d[k]删除键为k的项;
k in d检查d中是否含有键为k的项。


In [4]:
x=[]
x[42]='hello'


---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-4-f0295807ecda> in <module>()
      1 x=[]
----> 2 x[42]='hello'

IndexError: list assignment index out of range

In [5]:
x={}
x[42]='hello'
x


Out[5]:
{42: 'hello'}

上面将字符串'hello'关联到一个空列表的42号位置上—这显然是不可能的,因为这个位置根本不存在。为了将其变为可能,必须用[None]*43或者其他方式初始化x,而不能仅使用[]。但是,可将'hello'关联到空字典的键42上。

5.4 字典的格式化字符串

字典的格式化就是在每个转换说明符中的%字符后面,可以加上(用圆括号括起来的)键,后面再跟上其他说明元素。


In [6]:
phonebook={'Alice':'2341','Beth':9102}
phonebook


Out[6]:
{'Alice': '2341', 'Beth': 9102}

In [7]:
"Beth's phone number is %(Beth)s." % phonebook


Out[7]:
"Beth's phone number is 9102."

5.5 字典方法

1. clear
clear方法清除字典中所有的项。这是个原地操作(类似于list.sort),所以无返回值(或返回None)。

2. get
get方法是个更宽松的访问字典项的方法。一般来说,如果试图访问字典中不存在的项时会出错:


In [8]:
d={}
print d['name']


---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-8-4f402a46f272> in <module>()
      1 d={}
----> 2 print d['name']

KeyError: 'name'

而用get就不会:


In [9]:
print d.get('name')


None

可以看到,当使用get访问一个不存在的键时,没有任何异常,而得到了None值,还可以自定义”默认“值,替换None:


In [10]:
d.get('name','N/A')


Out[10]:
'N/A'

3. has_key
has_key方法可以检测字典中是否含有给出的键。表达式d.has_key(k)相当于表达式k in d。

4. items和iteritems
items方法将所有字典项以列表方式返回,这些列表项中的每一项都来自于(键,值)。但是项在返回时并没有特殊的顺序。


In [1]:
d={'title':'Python web site','url':'http://www.python.org','spam':0}
d.items()


Out[1]:
[('url', 'http://www.python.org'), ('spam', 0), ('title', 'Python web site')]

iteritems方法的作用大致相同,但是会返回一个迭代器对象而不是列表:


In [2]:
it=d.iteritems()
it


Out[2]:
<dictionary-itemiterator at 0x4324408>

In [3]:
list(it)  #Convert the iterator to a list


Out[3]:
[('url', 'http://www.python.org'), ('spam', 0), ('title', 'Python web site')]

在很多情况下使用iteritems更高效(尤其是想要迭代结果的情况下)。

5. keys和iterkeys
keys方法将字典中的键以列表形式返回,而iterkeys则返回针对键的迭代器。


In [4]:
d.keys()


Out[4]:
['url', 'spam', 'title']

In [5]:
m=d.iterkeys()
m


Out[5]:
<dictionary-keyiterator at 0x43244a8>

In [6]:
list(m)


Out[6]:
['url', 'spam', 'title']

6. pop
pop方法用来获得对应于给定键的值,然后将这个键-值对从字典中移除。

7. values和itervalues
values方法以列表的形式返回字典中的值(itervalues返回值的迭代器)。

8. setdefault
setdefault方法在某种程度上类似于get方法,就是能够获得与给定键相关联的值,除此之外,setdefault还能在字典中不含有给定键的情况下设定相应的键值。


In [8]:
d={}
d.setdefault('name','N/A')
d


Out[8]:
{'name': 'N/A'}

In [9]:
d['name']='Gumby'
d.setdefault('name','N/A')


Out[9]:
'Gumby'

In [10]:
d


Out[10]:
{'name': 'Gumby'}

6 小结


In [ ]: