记录几个 Python 字典中的冷门操作
01. 键映射多个值
一个字典就是一个键对应一个单值的映射。如果你想要一个键映射多个值,那么你就需要将这多个值放到另外的容器中, 比如列表或者集合里面。比如,你可以像下面这样构造这样的字典:
d = {
'a' : [1, 2],
'b' : [3]
}
e = {
'a' : {1, 2},
'b' : {3}
}
按照常规的做法,你可能会这么做
d=dict()
d.setdefault('a',[]).append(1)
d.setdefault('a',[]).append(2)
d.setdefault('b',[]).append(3)
e=set()
e.setdefault('a',{}).add(1)
e.setdefault('a',{}).add(2)
e.setdefault('b',{}).add(3)
在这里有一种更加优雅的做法
from collections import defaultdict
d = defaultdict(list)
d['a'].append(1)
d['a'].append(2)
d['b'].append(4)
d = defaultdict(set)
d['a'].add(1)
d['a'].add(2)
d['b'].add(4)
02. 有顺序的字典
大家都知道,字典是无序的。但是不排除某些情况下,我们会需要让字典变得有序,比如序列化成字符串时。
在 collects 中同样也提供了一个数据结构(OrderedDict
),来实现这个需求。
from collections import OrderedDict
d = OrderedDict()
d['foo'] = 1
d['bar'] = 2
d['spam'] = 3
d['grok'] = 4
for k in d:
print(k, d[k])
import json
json.dumps(d)
输出如下
('foo', 1)
('bar', 2)
('spam', 3)
('grok', 4)
'{"foo": 1, "bar": 2, "spam": 3, "grok": 4}'
OrderedDict 内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元素插入进来的时候, 它会被放到链表的尾部。对于一个已经存在的键的重复赋值不会改变键的顺序。
需要注意的是,一个 OrderedDict 的大小是一个普通字典的两倍,因为它内部维护着另外一个链表。 所以如果你要构建一个需要大量 OrderedDict 实例的数据结构的时候(比如读取 100,000 行 CSV 数据到一个 OrderedDict 列表中去), 那么你就得仔细权衡一下是否使用 OrderedDict 带来的好处要大过额外内存消耗的影响。
03. 键值的反转
首先需要了解了 zip
这个函数就好了。他可以将两个列表(当然其他用途不止两个,这里只是针对字典)重新组合。最后使用 dict 转换为字典。
>>> keys = ['name', 'age', 'food']
>>> values = ['Monty', 42, 'spam']
>>>
>>> zip(keys, values)
[('name', 'Monty'), ('age', 42), ('food', 'spam')]
>>>
>>> dict(zip(keys, values))
{'food': 'spam', 'age': 42, 'name': 'Monty'}
理解了 zip ,键值的反转,就变得容易了。只要把key和values的位置对调一下即可。
>>> d={'food': 'spam', 'age': 42, 'name': 'Monty'}
>>> zip(d.values(), d.keys())
[('spam', 'food'), (42, 'age'), ('Monty', 'name')]
>>>
>>> dict(zip(d.values(), d.keys()))
{42: 'age', 'Monty': 'name', 'spam': 'food'}
04. 求最大值对应的键
假设现在有一个字典,里面存放着众多水果的价格。
>>>prices={"Apple": 6, "Mango": 7, "Pear":3}
现在要找出,哪一种水果是最贵的。你会发现不太好找
一种思路是,可以借助上面的zip,将value调到前面来,再max
>>> max(zip(prices.values(), prices.keys()))
(7, 'Mango')
但是始终不太优雅。
这里还可以这样使用max函数。
>>> max(prices, key=lambda k:prices[k])
'Mango'