Python的数据结构

list 列表

Python内置的一种数据类型是列表:list。list是一种有序的集合,可以随时添加和删除其中的元素,而且元素可为数字、字符串、列表、元组、字典、布尔值。如下,test就是一个列表:

>>> test = ['string',1,2,{'dicts':1},(1,2),['lists',1],True]
>>> test
['string', 1, 2, {'dicts': 1}, (1, 2), ['lists', 1],True]
>>> 

可用len()函数获取列表的长度:

>>> b = len(test)
>>> b
6
>>>         

用索引来访问list中每一个位置的元素,记得索引是从0开始的:

>>> b = test[0]
>>> b
'string'
>>> 

当索引超出了范围时,Python会报一个IndexError错误,所以,要确保索引不要越界,记得最后一个元素的索引是len(test) - 1。

>>> test = ['string',1,2,{'dicts':1},(1,2),['lists',1]]
>>> b = test[5]
>>> b
['lists', 1]
>>> 
>>> b = test[6]

Traceback (most recent call last):
  File "<pyshell#156>", line 1, in <module>
    b = test[6]
IndexError: list index out of range
>>>         

list是一个可变的有序表,所以,可以往list中追加元素到末尾:

>>> test = ['string',1,2,{'dicts':1},(1,2),['lists',1]]
>>> test.append(9)
>>> test
['string', 1, 2, {'dicts': 1}, (1, 2), ['lists', 1], 9]
>>>         

也可以把元素插入到指定的位置,比如索引号为1的位置:

>>> test = ['string',1,2,{'dicts':1},(1,2),['lists',1]]
>>> test.insert(1,'ning')
>>> test
['string', 'ning', 1, 2, {'dicts': 1}, (1, 2), ['lists', 1]]
>>> 

要删除list末尾的元素,用pop()方法:

>>> test = ['string',1,2,{'dicts':1},(1,2),['lists',1]]
>>> test.pop()
['lists', 1]
>>> test
['string', 1, 2, {'dicts': 1}, (1, 2)]
>>> 

要删除指定位置的元素,用pop(i)方法,其中i是索引位置:

>>> test = ['string',1,2,{'dicts':1},(1,2),['lists',1]]
>>> test.pop(1)
1
>>> test
['string', 2, {'dicts': 1}, (1, 2), ['lists', 1]]
>>> 

要把某个元素替换成别的元素,可以直接赋值给对应的索引位置:

>>> test = ['string',1,2,{'dicts':1},(1,2),['lists',1]]
>>> test[0]='ning'
>>> test
['ning', 1, 2, {'dicts': 1}, (1, 2), ['lists', 1]]
>>> 

tuple 元组

另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改。
现在,test这个tuple不能变了,它也没有append(),insert()这样的方法。其他获取元素的方法和list是一样的,你可以正常地使用test[0],test[-1],但不能赋值成另外的元素。

>>> test = ('chen',1,True)
>>> type(test)
<type 'tuple'>
>>> test[0]
'chen'
>>> test[1]
1
>>> test.append('no')

Traceback (most recent call last):
  File "<pyshell#194>", line 1, in <module>
    test.append('no')
AttributeError: 'tuple' object has no attribute 'append'
>>> 

不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。
tuple的陷阱:当你定义一个tuple时,在定义的时候,tuple的元素就必须被确定下来,如果要定义一个空的tuple,可以写成(),比如:

>>> test = (1,2,3,4,5)
>>> test
(1, 2, 3, 4, 5)
>>> 

>>> test = ()
>>> test
()
>>> 

但是,要定义一个只有1个元素的tuple,如果你如下定义,那么他只是一个数字类型,并不是元组,这是因为括号()既可以表示tuple,又可以表示数学公式中的小括号,这就产生了歧义,因此,Python规定,这种情况下,按小括号进行计算,计算结果自然是1。要想让他变成一个元组,就在1后边加个逗号(1,)来消除歧义就可以了:

>>> test = (1)
>>> test
1
>>> type(test)
<type 'int'>
>>> 

>>> test = (1,)
>>> type(test)
<type 'tuple'>
>>> test
(1,)
>>> 

最后再说一个让元组‘可变’的方法

>>> test = ('a','b',['hello','world'])
>>> type(test)
<type 'tuple'>
>>> test[2][1] = 'ni hao'
>>> test[2][1] = 'shi jie'
>>> test
('a', 'b', ['hello', 'shi jie'])
>>> 

表面上看,tuple的元素确实变了,但其实变的不是tuple的元素,而是list的元素。tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向’a’,就不能改成指向’b’,指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!

理解了“指向不变”后,要创建一个内容也不变的tuple怎么做?那就必须保证tuple的每一个元素本身也不能变。

dict 字典

Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。
举个例子,假设要根据员工的名字查找对应的电话号码,如果用list实现,需要两个list:

>>> employee = ['zhang san','li si','wang gang dan']
>>> phone = [521521521,741741741,888888888]
>>> 

给定一个名字,要查找对应的电话号码,就先要在employee中找到对应的位置,再从phone取出对应的电话号码,list越长,耗时越长。
如果用dict实现,只需要一个“名字”-“电话号码”的对照表,直接根据名字查找成绩,无论这个表有多大,查找速度都不会变慢。用Python写一个dict如下:

>>> d = {'zhang san':521521521,'li si':741741741,'wang gang dan':888888888}
>>> d['wang gang dan']
888888888
>>> 

为什么dict查找速度这么快?因为dict的实现原理和查字典是一样的。假设字典包含了1万个汉字,我们要查某一个字,一个办法是把字典从第一页往后翻,直到找到我们想要的字为止,这种方法就是在list中查找元素的方法,list越大,查找越慢。
第二种方法是先在字典的索引表里(比如部首表)查这个字对应的页码,然后直接翻到该页,找到这个字。无论找哪个字,这种查找速度都非常快,不会随着字典大小的增加而变慢。
dict就是第二种实现方式,给定一个名字,比如’wang gang dan’,dict在内部就可以直接计算出wang gang dan对应的存放成绩的“页码”,也就是888888888这个数字存放的内存地址,直接取出来,所以速度非常快。
你可以猜到,这种key-value存储方式,在放进去的时候,必须根据key算出value的存放位置,这样,取的时候才能根据key直接拿到value。
把数据放入dict的方法,除了初始化时指定外,还可以通过key放入:

>>> d = {'zhang san':521521521,'li si':741741741,'wang gang dan':888888888}
>>> d['python'] = 999999999
>>> d['python']
999999999
>>> d
{'python': 999999999, 'zhang san': 521521521, 'wang gang dan': 888888888, 'li si': 741741741}
>>> 

由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值覆盖掉:

>>> d = {'zhang san':521521521,'li si':741741741,'wang gang dan':888888888}
>>> d['zhang san'] = 111111111
>>> d
{'zhang san': 111111111, 'wang gang dan': 888888888, 'li si': 741741741}
>>> d['zhang san'] = 222222222
>>> d
{'zhang san': 222222222, 'wang gang dan': 888888888, 'li si': 741741741}
>>> 

如果key不存在,dict就会报错:

>>> d = {'zhang san':521521521,'li si':741741741,'wang gang dan':888888888}
>>> d['!@#$%^&*']

Traceback (most recent call last):
  File "<pyshell#239>", line 1, in <module>
    d['!@#$%^&*']
KeyError: '!@#$%^&*'
>>> 

要避免key不存在的错误,有两种办法,一是通过in判断key是否存在:

>>> d = {'zhang san':521521521,'li si':741741741,'wang gang dan':888888888}
>>> '!@#$%^&*' in d
False
>>> 

通过dict提供的get方法,如果key不存在,可以返回None,或者自己指定的value:

>>> d = {'zhang san':521521521,'li si':741741741,'wang gang dan':888888888}
>>> d.get('!@#$%^&*')
>>>             # 返回None的时候Python的交互式命令行不显示结果
>>> d.get('!@#$%^&*',1)
1
>>> 

要删除一个key,用pop(key)方法,对应的value也会从dict中删除:

>>> d = {'zhang san':521521521,'li si':741741741,'wang gang dan':888888888}
>>> d.pop('zhang san')
521521521
>>> d
{'wang gang dan': 888888888, 'li si': 741741741}
>>> 

set 集合

set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。

要创建一个set,需要提供一个list作为输入集合:

>>> test = set([1,2,3])
>>> test
set([1, 2, 3])
>>> type(test)
<type 'set'>
>>> 

注意,传入的参数[1, 2, 3]是一个list,而显示的{1, 2, 3}只是告诉你这个set内部有1,2,3这3个元素,显示的顺序也不表示set是有序的。

重复元素在set中自动被过滤:

>>> test = set([1,2,2,3,3,3])
>>> test
set([1, 2, 3])
>>> 

通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果:

>>> test = set([1,2,3])
>>> test
set([1, 2, 3])
>>> test.add(4)
>>> test
set([1, 2, 3, 4])
>>> test.add(4)
>>> test
set([1, 2, 3, 4])
>>> 

通过remove(key)方法可以删除元素:

>>> test = set([1,2,3])
>>> test
set([1, 2, 3])
>>> test.remove(3)
>>> test
set([1, 2])
>>> 

set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作:

>>> test1 = set([1,2,3])
>>> test1
set([1, 2, 3])
>>> test2 = set([2,3,4])
>>> test2
set([2, 3, 4])
>>> test1 & test2
set([2, 3])
>>> test1 | test2
set([1, 2, 3, 4])
>>> 

set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。试试把list放入set,看看是否会报错。

>>> test = set([1,2,3,[4,5]])

Traceback (most recent call last):
  File "<pyshell#283>", line 1, in <module>
    test = set([1,2,3,[4,5]])
TypeError: unhashable type: 'list'
>>> 

字符串/元组/列表/字典互转

1、字典

>>>dicts = {'name': 'Zara', 'age': 7, 'class': 'First'}

字典转为字符串:

>>>print type(str(dicts)), str(dicts)
<type 'str'> {'age': 7, 'name': 'Zara', 'class': 'First'}

字典可以转为元组:

>>>print tuple(dicts)
('age', 'name', 'class')

字典可以转为元组:

>>>print tuple(dicts.values())
(7, 'Zara', 'First')

字典转为列表:

>>>print list(dicts)
['age', 'name', 'class']

字典转为列表

>>>print dicts.values
<built-in method values of dict object at 0x0000000002E6D6A8>

2、元组

>>>tup=(1, 2, 3, 4, 5)

元组转为字符串:

>>>print tup.__str__()
(1, 2, 3, 4, 5)

元组转为列表:

>>>print list(tup)
[1, 2, 3, 4, 5]

元组不可以转为字典

3、列表

>>>nums=[1, 3, 5, 7, 8, 13, 20];

列表转为字符串:

>>>print str(nums)
[1, 3, 5, 7, 8, 13, 20]

列表转为元组:

>>>print tuple(nums)
(1, 3, 5, 7, 8, 13, 20)

列表不可以转为字典

4、字符串
字符串转为元组:

>>>print tuple(eval("(1,2,3)"))
(1, 2, 3)

字符串转为列表:

>>>print list(eval("(1,2,3)"))
[1, 2, 3]

字符串转为字典:

>>>print type(eval("{'name':'ljq', 'age':24}"))
<type 'dict'>

热评文章