Chapter3DictionariesandSets[toc]字典推导你可能见过列表推导,但你没见过字典推导,2.7新增:d={key:valuefor(key,value)initerable}举个例子:iterable=[(1,'hello'),(2,'world'),(3,'happy')]d={key:valuefor(key,value)initerable}print(d)#{1:'hello',2:'world',3:'happy'}setdefault用法使用setdefault处理丢失的键简单示例:d={'a':1,'b':2}d['c']=3#如果没有原值则设置,否则保持原值不变d.setdefault('c',4)print(d)#{'a':1,'b':2,'c':3}字典也有get方法,如下:d={'a':1,'b':2}#d['c']=3#使用默认值get方法设置的不会改变原来的字典a=d.get('c',4)print(a)#4print(d)#{'a':1,'b':2}可以看到两个前者的区别:get方法设置的默认值不会改变原来的d字典,但是setdefault设置的默认值会改变原来字典的值。再看一个例子:some_dict={'abc':'a','cdf':'b','gh':'a','fh':'g','hfz':'g'}new_dict={}fork,vinsome_dict.items():new_dict.setdefault(v,[]).append(k)print(new_dict)#{'a':['abc','gh'],'b':['cdf'],'g':['fh','hfz']}defaultdict用法所有映射类型在处理缺失键时都会涉及__missing__方法。这就是为什么这种方法被称为“缺失”的原因。虽然基类dict没有定义这个方法,但是dict知道有这么个东西存在。例如:classDict(dict):def__missing__(self,key):self[key]=[]returnself[key]dct=Dict()print(dct["foo"])#[]dct["foo".append(1)dct["foo"].append(2)print(dct["foo"])#[1,2]defaultdict是collections模块下的一个工厂函数,用于构建字典对象,并接收一个函数(可调用)对象作为参数。参数返回的类型是什么,key对应的值是什么fromcollectionsimportdefaultdict#参数是list,会建一个默认值为list的字典,#比如result['的值a']默认是列表对象。dct=defaultdict(list)print(dct)#defaultdict(,{})print(dct["a"])#[]dct["a"].append("hello")print(dct)#defaultdict(,{'a':['hello']})看一个例子:fromcollectionsimportdefaultdictresult=defaultdict(list)data=[("p",1),("p",2),("p",3),("h",1),("h",2),("h",3)]for(key,value)indata:result[key.append(value)print(result)#defaultdict(,{'p':[1,2,3],'h':[1,2,3]})print(dict(result))#{'p':[1,2,3],'h':[1,2,3]}再看一个例子:#经典的统计names=['leo','sam','jack','peter','joe','susan']#要变成这样:{3:['leo','sam','joe'],4:['jack'],5:['peter','susan']}#badnums=[len(n)forninnames]contain={}fork1,k2inzip(nums,names):print(k1,k2)ifk1notincontain:contain[k1]=[k2]else:contain[k1].append(k2)print(contain)print("#"*10)#betterfromcollectionsimportdefaultdictd=defaultdict(list)fornameinnames:key=len(name)d[key].append(name)print(dict(d))default性能效率检测importtimeitfromcollectionsimportdefaultdictdefway1():d={}chars=['a','b','c','c','a','a']*10000forcinchars:ifcind:d[c]+=1else:d[c]=1returnddefway2():d=defaultdict(int)chars=['a','b','c','c','a','a']*10000forcinchars:d[c]+=1returndif__name__=="__main__":t1=timeit.timeit("way1",setup="from__main__importway1",number=10)print(t1)#6e-07(表示6x10^(-7),即6x0.0000001,如果写成6e07表示6x10^7)t2=timeit.timeit("way2",setup="from__main__importway2",number=10)print(t2)#4.000000000000097e-07字典的使用,要学会使用defaultdict相反,一个是默认值非常安全。如果访问不存在的key,则不会报错;另一个是Python的性能会得到很大的提升。只要改变字典的数据结构,性能就会有很大的提升。字典python字典dict的变体默认是无序的,集合中请使用orderdictpython2代码:importcollectionsd={}d['name']='zhf'd['age']=33d['city']='chengdu'fork,vind.items():printk,va=collections.OrderedDict()a['name']='zhf'a['age']=33a['city']='chengdu'print"*"*10fork,vina.items():printk,v返回结果:citychengduage33namezhf************namezhfage33citychengdupython3.6.7code:importcollectionsd={}d['name']='zhf'd['age']=33d['city']='chengdu'fork,vind.items():print(k,v)a=collections.OrderedDict()a['name']='zhf'a['age']=33a['city']='chengdu'print("*"*10)fork,vina.items():print(k,v)results:namezhfage33citychengdu**********namezhfage33citychengdu可以看到3.6版本的Python让dict更加紧凑,关键字集合更加有序。计数器用法的简单示例:importcollectionsstring="aaabbbc"ct=collections.Counter(string)print(ct)#Counter({'a':3,'b':3,'c':1})print(dict(ct))#{'a':3,'b':3,'c':1}ct.update('abcdef')print(dict(ct))#{'a':4,'b':4,'c':2,'d':1,'e':1,'f':1}集合的本质是许多唯一对象的集合,所以集合可以删除重复元素d=['abc','def','abc','def']s=set(d)print(s)#{'def','abc'}假设有2个集合a和b,需要统计集合a中哪些元素也出现在集合b中。如果不使用sets,代码只能写成如下形式:a=['abc','def','aaa']b=['abc','bbb','ccc','def']fornina:ifninb:print(n)但是如果你使用集合,你就不用担心了。在集合中。a|b返回一个集合,a&b返回一个交集。a-b返回差异集。-差集是指属于A但不属于B的组合a=['abc','def','aaa']b=['abc','bbb','ccc','def']print(set(a)&set(b))print(set(a)|set(b))print(set(a)-set(b))#等于print(set(a).difference(b))resultreturn:{'def','abc'}{'aaa','def','ccc','abc','bbb'}{'aaa'}字典、list和set运算效率比较Listintersection代码:从时间导入timet=time()lista=[1,2,3,4,5,6,7,8,9,13,34,53,42,44]listb=[2,4,6,9,23]intersection=[]foriinrange(1000000):forainlista:forbinlistb:ifa==b:intersection.append(a)print("总运行时间:%s"%(time()-t))#totalruntime:5.015027046203613setintersectioncode:fromtimeimporttimet=time()lista=[1,2,3,4,5,6,7,8,9,13,34,53,42,44]listb=[2,4,6,9,23]intersection=[]foriinrange(1000000):list(set(lista)&set(listb))print("总运行时间:%s"%(time()-t))#总运行时间:1.0969467163085938字典代码:来自timeimporttimet=time()list=['a','b','is','python','jason','hello','hill','with','phone','test','dfdf','apple','pddf','ind','basic','none','baecr','var','bana','dd','wrd']#list=dict.fromkeys(list,True)#总运行时间:0.9107456207275391print(list)filter=[]foriinrange(1000000):forfindin['is','hat','new','list','old','.']:如果发现不在列表中:filter.append(find)print("totalruntime:%s"%(time()-t))#总运行时间:2.0197031497955322Python字典使用哈希表,所以查找操作的复杂度为O(1),列表实际上是一个数组。在链表中,查找需要遍历整个链表,其复杂度为O(n)。因此,搜索和访问成员等操作比列表更快。因此,当需要多个数据成员进行频繁的查找或访问时,使用dict而不是lists是更好的选择。一个好的算法可以对性能起到关键作用。因此,性能提升的首要点是改进算法。该算法的时间复杂度顺序为:O(1)->O(lgn)->O(nlgn)->O(n^2)->O(n^3)->O(n^k)->O(k^n)->O(n!)