1.多值映射
一般的字典都是一个键对应一个值。为了想要实现多值映射就需要一个容器,列表或者集合,比如:
d = {‘a‘ : [1, 2, 3],‘b‘ : [4, 5]}e = {‘a‘ : {1, 2, 3},‘b‘ : {4, 5}}
如果要实现上面的,就必须先对键值进行初始化为列表或者集合:
d={} d.setdefault(‘a‘, []).append(1)
如果我们用collections
模块下的defaultdict来实现就简单好多
d = defaultdict(list)for key, value in pairs: d[key].append(value)
如果自己实现呢?就是这样的:
d = {}for key, value in pairs:if key not in d: d[key] = [] d[key].append(value)
2.字典排序
如果需要生成一个有顺序的字典,可以使用collections
模块中的OrderedDict
,会按照输入的顺序排序:
from collections import OrderedDictdef ordered_dict(): d = OrderedDict() d[‘foo‘] = 1 d[‘bar‘] = 2 d[‘spam‘] = 3 d[‘grok‘] = 4 # Outputs "foo 1", "bar 2", "spam 3", "grok 4" for key in d:print(key, d[key])
当然,一个OrseredDict的大小是一个普通字典的两倍,因为它内部维护着另外一条链表
3.字典计算
当求最大值,最小值或者排序时,通常用到zip()函数将键和值翻转,然后进行比较或者排序
prices = {‘ACME‘: 45.23,‘AAPL‘: 612.78,‘IBM‘: 205.55,‘HPQ‘: 37.20,‘FB‘: 10.75} min(zip(prices.values(),prices.keys())) sorted(zip(prices.values(),prices.keys()))
注:zip函数创建的是一个只能访问一次的迭代器
prices_and_names = zip(prices.values(), prices.keys())print(min(prices_and_names)) # OKprint(max(prices_and_names)) # ValueError: max() arg is an empty sequence
也可以在 min() 和 max() 函数中提供 key 函数参数来获取最小值或最大值对应的键的信息
min(prices, key=lambda k: prices[k]) # Returns ‘FB‘
4.找两个字典的相同点
a = {‘x‘ : 1,‘y‘ : 2,‘z‘ : 3}b = {‘w‘ : 10,‘x‘ : 11,‘y‘ : 2}
a.keys() & b.keys() # { ‘x‘, ‘y‘ } a.keys() - b.keys() # { ‘z‘ } a.items() & b.items() # { (‘y‘, 2) }
字典过滤:
c = {key:a[key] for key in a.keys() - {‘z‘, ‘w‘}}# c is {‘x‘: 1, ‘y‘: 2}
字典的items()
和keys()
都支持集合操作交,并,差运算~
5.根据某个或某几个字典字段来排序这个列表
通过使用 operator
模块的 itemgetter
函数,可以非常容易的排序这样的数据结构。
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}]from operator import itemgetter rows_by_fname = sorted(rows, key=itemgetter(‘fname‘)) rows_by_lfname = sorted(rows, key=itemgetter(‘lname‘,‘fname‘))
当然也可以用匿名函数代替itemgetter()
,但是,使用itemgetter()
方式会运行的稍微快点 ``` rowsbyfname = sorted(rows, key=lambda r: r[‘fname‘]) rowsbylfname = sorted(rows, key=lambda r: (r[‘lname‘],r[‘fname‘]))
以上同样适用于min() max()### 6排序不支持原生比较的对象 operator.attrgetter()
class User: def init(self, userid): self.userid = userid def repr(self): return ‘User({})‘.format(self.userid) def sortnotcompare(): users = [User(23), User(3), User(99)] print(users) print(sorted(users, key=lambda u: u.userid)) ```
另外一种方式是使用 operator.attrgetter()
来代替lambda函数:
>>> from operator import attrgetter>>> sorted(users, key=attrgetter(‘user_id‘)) [User(3), User(23), User(99)]
7.通过某字段分组
groupby()
函数扫描整个序列并且查找连续相同值(或者根据指定key函数返回值相同)的元素序列。 首先需要按照指定的字段(这里就是 date
)排序, 然后调用 itertools.groupby()
函数:
from operator import itemgetterfrom itertools import groupby# Sort by the desired field firstrows.sort(key=itemgetter(‘date‘))# Iterate in groupsfor date, items in groupby(rows, key=itemgetter(‘date‘)): print(date) for i in items: print(‘ ‘, i)
8.合并多个字典
一个非常简单的解决方案就是使用 collections
模块中的 ChainMap
类 一个 ChainMap
接受多个字典并将它们在逻辑上变为一个字典。 然后,这些字典并不是真的合并在一起了, ChainMap
类只是在内部创建了一个容纳这些字典的列表 并重新定义了一些常见的字典操作来遍历这个列表。大部分字典操作都是可以正常使用的 作为 ChainMap
的替代,你可能会考虑使用 update()
方法将两个字典合并。但是它需要你创建一个完全不同的字典对象(或者是破坏现有字典结构)。 同时,如果原字典做了更新,这种改变不会反应到新的合并字典中去。