上一章我们介绍了python中的列表,本章介绍其余三种数据结构:字典、集合和元组。
1、字典
字典有两个特点:其一,字典是由大括号{}包围的;其二,字典的每一个元素的模式都是“键:值”,而不是“键=值”,两个元素之间用逗号,隔开。
注意,字典初始化的顺序不会保持,在初始化后,再次查看字典时,元素顺序可能变化。
一般访问字典的数据时,使用中括号记法,中括号中是键,使用键来访问其关联的数据值。
python字典的底层是一个大小可变的散列表。
空字典的初始化就是一个空的大括号。
python中有+=1操作符,但是没有++操作符。
当利用for循环显示字典时,如果使用以下这种方式:
vowels={'a':0,'e':0,'i':0,'o':0,'u':0}
for letter in vowels:
print(letter)
那么其效果如下图:
只显示了键,而与键关联的值并没有显示出来,这说明这种方式并不是想要的。这是因为,用for循环迭代处理一个字典时,解释器只处理字典的键,因此,要访问键和其对应的值,应按如下方式:
vowels={'a':0,'e':0,'i':0,'o':0,'u':0}
for letter in vowels:
print(letter,':',vowels[letter])
其效果如下图:
还有另一种方式,不使用vowels[letter]这种方式,而是使用字典自带的函数items,这一函数会返回一个对应字典的键值对列表, 即一个n行2列的列表,然后用两个变量保存每行的两个元素即可。
如图,函数返回的是一个元素为元组的列表。这样,访问键值对的for循环可以如下所示:
vowels={'a':0,'e':0,'i':0,'o':0,'u':0}
for c,v in vowels.items():
print(c,':',v)
其效果如下:
可以利用sorted函数,该函数会返回字典的一个有序版本,而不会改变原来的字典的顺序。因此每次需要有序输出时,都要再次调用该函数。
注意,如果我们没有对字典中的某个键初始化,即该键在字典中不存在,那么访问该键对应的值则会报错KeyError。因此在访问某个键之前,要先判断这个键在不在字典中,一般使用in。in可以返回True或False,注意T和F要大写,只有大写才能表示真与假,小写的话就会被认为是变量,而不是布尔值。其代码如下:
if 'banana' in fruits:
fruits['banana']+=1
else
fruits['banana']=1
也就是说,在字典fruits中,如果键banana不存在,那么会新建一个键,并设置值为1;如果存在,则其值加一。此代码一般应用于频度计数。
我们也可以使用not in来代替上面的代码,如下:
if 'pears' not in fruits:
fruits['pears']=0
fruits['pears']+=1
每次都会执行值加一,但是在加一前要检查键是否存在,若不存在,就初始化为0。
注意这里if-not in的两行代码,由于它太常见,因此字典中有一个函数setdefault代替该函数,如下:
fruits.setfault('pears',0)
fruits['pears']+=1
所以人还是够懒的,四行变三行再变两行。setfault函数有两个参数,第一个是键,第二个是值。虽然它用于初始化,但是循环体中要有它,每次循环都要执行一次。这样就可以杜绝KeyError异常。
当我们要存储一个多行多列的表时,多行两列的字典不够用了,因此要使用元素为字典的字典来储存,也称嵌套链表。
这种字典中,每个元素都是字典,元素字典会储存一行的元素,外面的字典会储存多行。当访问这种字典的一个元素时,类似二维数组,像这样:
People['name']['job']
当我们想要利用print输出嵌套链表时,总会发现输出的很复杂,因此可以import一个pprint模块,使用pprint函数输出嵌套链表,会很美观。但是注意一点,二维数组的下标也可先行再列,也可以先列再行,但是这里就只能先字典元素,再字典元素的字典元素了。
2、集合
集合的一大特性是无重复元素。对集合的查找操作要比对列表的查找快的多,因此集合是查找首选的数据结构。
集合也是用大括号{}包围,与字典的不同之处是它的元素中没有冒号:。另外,集合也没有顺序可言。
集合的初始化有两种方法,如下:
vowels={'a','a','a','e','i','i','i','o','u','u'}
#或
vowels=set('aaaeiiouu')
前者是直接初始化,后者是利用set函数初始化。无论哪种初始化,最后剩下的元素就只有一个,而不会报错。
集合主要有三个函数:并集、交集、差集。
并集函数:union,A.union(B)将集合A与B合并,并返回一个新的集合,而A、B不会变化。
差集函数:difference,A.difference(B)返回一个集合,是A与B中,在A中存在而在B中不存在的元素。
交集函数,intersection,A.intersection(B)返回一个集合,在A和B中共有的元素。
3、元组
元组是用()包围的。在将元组初始化之后,就不能再将其改变。
注意只有一个对象的元组,若元组只有一个对象,那么在这个对象之后一定有一个逗号,,否则编译器会把这个元组错认为是一个变量。
元组中的元素如果有列表,虽然不能修改元组元素,但是可以修改列表,这样元组元素也会更新。
4、数据结构的转换
四种数据结构还有字符串均可以互相转换,代码如下:
num_list=[1,2,3]
num_dic={'first':1,'second':2,'third':3}
num_set={1,2,3}
num_tuple=(1,2,3)
num="123"
print("转化为list")
print(list(num_dic))
print(list(num_dic.values()))
print(list(num_set))
print(list(num_tuple))
print(list(num))
print("转化为set")
print(set(num_list))
print(set(num_dic))
print(set(num_dic.values()))
print(set(num_tuple))
print(set(num))
print("转化为tuple")
print(tuple(num_list))
print(tuple(num_dic))
print(tuple(num_dic.values()))
print(tuple(num_set))
print(tuple(num))
print("转化为dict")
print(dict(zip(num_list,num_list)))
print(dict(zip(num_set,num_set)))
print(dict(zip(num_tuple,num_tuple)))
print(dict(zip(num,num)))
print("转化为str")
print(''.join(str(num_list)))
print(''.join(str(num_dic)))
print(''.join(str(num_dic.values())))
print(''.join(str(num_set)))
print(''.join(str(num_tuple)))
print("转化为str,完美版")
print(''.join(str(i) for i in num_list))
print(' '.join(str(i) for i in num_dic))
print(' '.join(str(i) for i in num_dic.values()))
print(' '.join(str(i) for i in num_set))
print(' '.join(str(i) for i in num_tuple))
其效果如下:
有以下几点需要注意:
字典转换成其他结构,如果没有预先说明,那么就不管值,只转换键;要想转换值,那需要调用values方法。
其他结构转换为字典时,只用zip不够,因为zip返回的是一个迭代器,应将这个迭代器作为dict的参数,这样返回的才是字典。
其他结构转换为字符串时,使用join函数,注意以下几点:
join函数前面的''是转换成字符串之后各元素间的分隔符,可以自定义,如果没有那就是一整串;
join函数要求参数中所有元素必须都是字符串类型,如果不是,需要用str函数转换;
对list等直接用str转换的后果就是,list返回的是一个列表,列表有[],那str会把[]也变成字符,这样不太符合我们的要求;
为了在结果中不显示[]等,可以用列表生成式,把每个元素分别变成str。
注意,list、dict、set、tuple属于BIF,即内置函数,它们用于创建数据结构。