Python 进阶编程之字典的高级用法
一、 collections 中 defaultdict 的使用 1.1 字典的键映射多个值
将下面的列表转成字典
[Python] 纯文本查看 复制代码
1
|
l = [( 'a' , 2 ),( 'b' , 3 ),( 'a' , 1 ),( 'b' , 4 ),( 'a' , 3 ),( 'a' , 1 ),( 'b' , 3 )][ / size][ / color][ / align] |
一个字典就是一个键对应一个单值的映射,而上面的列表中有相同键。如果你想要一个键映射多个值,那么就需要将这多个值放到另外的序列中,比如 list 或者 set 里面,像下面这样:
[Python] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
|
d = { 'a' : [ 1 , 2 , 3 ], 'b' : [ 4 , 5 ] } e = { 'a' : { 1 , 2 , 3 }, 'b' : { 4 , 5 } } |
[Python] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
|
In [ 1 ]: l = [( 'a' , 2 ),( 'b' , 3 ),( 'a' , 1 ),( 'b' , 4 ),( 'a' , 3 ),( 'a' , 1 ),( 'b' , 3 )] In [ 2 ]: from collections import defaultdict In [ 3 ]: d = defaultdict( list ) In [ 4 ]: for key, value in l: ...: d[key].append(value) ...: In [ 5 ]: d Out[ 5 ]: defaultdict( list , { 'a' : [ 2 , 1 , 3 , 1 ], 'b' : [ 3 , 4 , 3 ]}) |
1.2 统计字典中某个值出现的次数
来源于微信交流群里一个朋友工作中的问题,列表中有很多字典,需要统计字典中相同的键对应的值的和
[Python] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
|
In [ 6 ]: d = defaultdict( int ) In [ 7 ]: objs = [{ 'F29958SVDK6' : 12 }, { 'F29958SVDK6' : 12 }, { 'F29958SVDK6' : 12 }, { 'F29958SVDK6' : 12 }, { 'F29958SVDK6' : 12 }] In [ 8 ]: for obj in objs: ...: for key,value in obj.items(): ...: d[key] + = value ...: In [ 9 ]: d Out[ 9 ]: defaultdict( int , { 'F29958SVDK6' : 60 }) |
二、collections 创建有序字典
字典dict是无序的,如果我们想要有序的dict,可以使用OrdereDict 。示例如下:
[Python] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
|
In [ 11 ]: from collections import OrderedDict[ / color][ / align] In [ 12 ]: d = OrderedDict() In [ 13 ]: d[ 'bar' ] = 2 In [ 14 ]: d[ 'non' ] = 8 In [ 15 ]: d[ 'sek' ] = 5 In [ 16 ]: d Out[ 17 ]: OrderedDict([( 'bar' , 2 ), ( 'non' , 8 ), ( 'sek' , 5 )]) |
OrderedDict 内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元 素插入进来的时候,它会被放到链表的尾部。对于一个已经存在的键的重复赋值不会 改变键的顺序。
需要注意的是,一个 OrderedDict 的大小是一个普通字典的两倍,因为它内部维 护着另外一个链表。所以如果你要构建一个需要大量 OrderedDict 实例的数据结构的 时候 (比如读取 100,000 行 CSV 数据到一个 OrderedDict 列表中去),那么你就得仔细权衡一下是否使用 OrderedDict 带来的好处要大过额外内存消耗的影响。
2.1 改变 key-value 的顺序 OrderedDict 是有序的字典,同时也能改变其顺序。比如我们想要改变有序的 OrderedDict 对象的 key-value 顺序,可以使用 move_to_end(key)。还是以上面创建的有序字典为例子
[Python] 纯文本查看 复制代码
1
2
3
4
|
In [ 18 ]: d.move_to_end( "bar" ) In [ 20 ]: d Out[ 20 ]: OrderedDict([( 'non' , 8 ), ( 'sek' , 5 ), ( 'bar' , 2 )]) |
可以看到之前排在第一位的 bar被移到最后一位了。move_to_end 还接收一个关键字参数 last。last 默认为 True,当 last = False 的时候,表示将该键移动到最前面!
2.2 删除 key_value
如果我们要删除有序字典中的 key-value, 可以使用 popitem 方法, popitem(last=True) 按照先进后出的顺序删除 dict中 的 key-value,popitem(last=False) 按照先进先出的规则删除 dict 中的 key-value。
[Python] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
|
In [ 42 ]: d Out[ 42 ]: OrderedDict([( 'bar' , 2 ), ( 'non' , 8 ), ( 'sek' , 5 )]) In [ 43 ]: d.popitem(last = False ) Out[ 43 ]: ( 'bar' , 2 ) In [ 44 ]: d Out[ 44 ]: OrderedDict([( 'non' , 8 ), ( 'sek' , 5 )]) |
三、字典排序
利用Python 内置函数 sorted 对字典的键或者值进行排序,首先来了解下 sorted 函数
[Python] 纯文本查看 复制代码
1
|
sorted (iterable, key = None , reverse = False ) |
参数说明:
iterable -- 可迭代对象
key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
3.1 按照 key 进行排序 理解了 sorted 函数就好办了,代码如下:[Python] 纯文本查看 复制代码
1
2
3
4
5
6
7
|
In [ 55 ]: d = { 'b' : 3 , 'a' : 4 , 'c' : 2 , 'd' : 1 } In [ 57 ]: d.items() Out[ 57 ]: dict_items([( 'b' , 3 ), ( 'a' , 4 ), ( 'c' , 2 ), ( 'd' , 1 )]) In [ 58 ]: sorted (d.items(), key = lambda i:i[ 0 ]) Out[ 58 ]: [( 'a' , 4 ), ( 'b' , 3 ), ( 'c' , 2 ), ( 'd' , 1 )] |
3.2 按照 value 进行排序
[Python] 纯文本查看 复制代码
1
2
|
In [ 59 ]: sorted (d.items(), key = lambda i:i[ 1 ]) Out[ 59 ]: [( 'd' , 1 ), ( 'c' , 2 ), ( 'b' , 3 ), ( 'a' , 4 )] |
四、通过某个关键字排序一个字典列表
假设你有一个字典列表, 如下:
[Python] 纯文本查看 复制代码
1
2
3
4
|
rows = [ { 'fname' : 'Brian' , 'lname' : 'Jones' , 'uid' : 1003 }, { 'fname' : 'David' , 'lname' : 'Beazley' , 'uid' : 1002 }, { 'fname' : 'John' , 'lname' : 'Cleese' , 'uid' : 1001 }, { 'fname' : 'Big' , 'lname' : 'Jones' , 'uid' : 1004 } ] |
你想根据某个或某几个字典字段来排序这个列表。
通过使用 operator 模块的 itemgetter 函数,可以非常容易的排序这样的数据结构,代码如下:
[Python] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
In [ 46 ]: from operator import itemgetter In [ 47 ]: rows_by_fname = sorted (rows, key = itemgetter( 'fname' )) In [ 48 ]: rows_by_fname Out[ 48 ]: [{ 'fname' : 'Big' , 'lname' : 'Jones' , 'uid' : 1004 }, { 'fname' : 'Brian' , 'lname' : 'Jones' , 'uid' : 1003 }, { 'fname' : 'David' , 'lname' : 'Beazley' , 'uid' : 1002 }, { 'fname' : 'John' , 'lname' : 'Cleese' , 'uid' : 1001 }] In [ 49 ]: rows_by_uid = sorted (rows, key = itemgetter( 'uid' )) In [ 50 ]: rows_by_uid Out[ 50 ]: [{ 'fname' : 'John' , 'lname' : 'Cleese' , 'uid' : 1001 }, { 'fname' : 'David' , 'lname' : 'Beazley' , 'uid' : 1002 }, { 'fname' : 'Brian' , 'lname' : 'Jones' , 'uid' : 1003 }, { 'fname' : 'Big' , 'lname' : 'Jones' , 'uid' : 1004 }] |
itemgetter() 函数也支持多个 keys,比如下面的代码:
[Python] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
|
In [ 52 ]: rows_by_lfname = sorted (rows, key = itemgetter( 'lname' , 'fname' )) In [ 53 ]: rows_by_fname Out[ 53 ]: [{ 'fname' : 'Big' , 'lname' : 'Jones' , 'uid' : 1004 }, { 'fname' : 'Brian' , 'lname' : 'Jones' , 'uid' : 1003 }, { 'fname' : 'David' , 'lname' : 'Beazley' , 'uid' : 1002 }, { 'fname' : 'John' , 'lname' : 'Cleese' , 'uid' : 1001 }] |