1.6 字典中的key映射多个值
映射的多个值需要放到另外的容器,如list、set等。
主要是collections模块的defaultdict
函数和dict自带的setdefault
函数
from collections import defaultdict
d = defaultdict(list)
d['a'].append(1)
d['a'].append(2)
d['b'].append(4)
d = {} # 一个普通的字典
d.setdefault('a', []).append(1)
d.setdefault('a', []).append(2)
d.setdefault('b', []).append(4)
两者的区别:defaultdict
函数会在访问的key不存在时也会创建映射实体如list等
setdefault
函数每次调用都得创建新的key的实例
1.7 字典排序
创建一个字典,在迭代和序列化的时候控制元素的排序
主要是用collections的OrderDict
类
from collections import OrderedDict
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])
主要用于序列化或编码成其他格式时有严格的顺序要求,如json编码
>>> import json
>>> json.dumps(d)
'{"foo": 1, "bar": 2, "spam": 3, "grok": 4}'
>>>
注意:OrderedDict
类的大小是普通字典的两倍,因为其内部还维护了一个双向链表
1.8 字典的运算
对字典的最大值、最小值、排序等运算
主要是zip()
和min() max() sorted()
函数的结合使用
其中zip()
函数将字典key和value反转,达到按照value的排序目的
这样做的原因是min() max() sorted()
这些计算函数只能作用于字典的key
min() max() sorted()
就将zip处理后创建的迭代器就行运算
prices = {
'ACME': 45.23,
'AAPL': 612.78,
'IBM': 205.55,
'HPQ': 37.20,
'FB': 10.75
}
min_price = min(zip(prices.values(), prices.keys()))
# min_price is (10.75, 'FB')
max_price = max(zip(prices.values(), prices.keys()))
# max_price is (612.78, 'AAPL')
prices_sorted = sorted(zip(prices.values(), prices.keys()))
# prices_sorted is [(10.75, 'FB'), (37.2, 'HPQ'),
# (45.23, 'ACME'), (205.55, 'IBM'),
# (612.78, 'AAPL')]
注意: zip()
函数创建的是一个只能访问一次的迭代器;在执行 min()
和 max()
操作的时候,如果恰巧最小或最大值有重复的,那么拥有最小或最大键的实体会返回
1.9 查找字典的相同点
主要使用字典的keys()
函数items()
函数的返回结果进行集合运算
a = {
'x' : 1,
'y' : 2,
'z' : 3
}
b = {
'w' : 10,
'x' : 11,
'y' : 2
}
# Find keys in common
a.keys() & b.keys() # { 'x', 'y' }
# Find keys in a that are not in b
a.keys() - b.keys() # { 'z' }
# Find (key,value) pairs in common
a.items() & b.items() # { ('y', 2) }
字典的 keys()
方法返回一个展现键集合的键视图对象,
字典的 items()
方法返回一个包含 (键,值) 对的元素视图对象
以上的两个对象都支持集合运算
字典的 values()
方法也是类似,但是它并不支持这里介绍的集合操作。是因为值视图不能保证所有的值互不相同,这样会导致某些集合操作会出现问题。可以先将返回值转换为set进行集合操作
1.10 删除序列中相同元素并保持顺序
不保持排序的话,仅仅用set()
函数就可以解决。
首先要了解hashable类型
、yield函数
,lambda函数
-
hashable类型
a.哈希表是在一个关键字和一个较大的数据之间建立映射的表,能使对一个数据序列的访问过程更加迅速有效。用作查询的关键字必须唯一且固定不变。
b.
immutable
属性,该属性指对象一经创建便不可修改。数据类型是integer,string,tuple都是不可更改的;list,dictionary,set是可更改的hashable ≈ imutable 可哈希 ≈ 不可变
因此,immutable的对象可以作为一个固定不变的对象,适合作为哈希表的索引,因而它们是hashable的。
*如果一个对象在其生命周期内,其哈希值从未改变(这需要一个__hash__()方法),并且可以与其他对象进行比较(这需要一个__eq__()或__cmp__()方法),那么这个对象就是可哈希的。哈希对象的相等意味着其哈希值的相等。
哈希性使得对象可以用作dictionary键和set成员,因为这些数据结构在内部使用了哈希值。
Python的所有不可变的内置对象都是可hashable的,但可变容器(如列表或字典)并非如此。对于用户定义的类的实例,默认情况下是可哈希的;它们都是不相等的,并且它们的哈希值都是id()*
-
yield函数
一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 _next()_)才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
def fab(max): n, a, b = 0, 0, 1 while n < max: yield b # print b a, b = b, a + b n = n + 1 >>> for n in fab(5): ... print n ... 1 1 2 3 5
-
lambda函数
匿名函数
lambda [arg1 [, agr2,.....argn]] : expression
1、单个参数的:
>>> g = lambda x : x ** 2
>>> print g(3)
9
2、多个参数的:
>>> g = lambda x, y, z : (x + y) ** z
>>> print g(1,2,2)
9
以上了解完毕后,开始处理删除序列相同元素并保持顺序
主要通过yield函数来实现顺序不变,
-
序列中元素是hashable的
def dedupe(items): seen = set() for item in items: if item not in seen: yield item seen.add(item)
输出
>>> a = [1, 5, 2, 1, 9, 1, 5, 10] >>> list(dedupe(a)) [1, 5, 2, 9, 10] >>>
-
序列中元素不是hashable的
先将不可序列化的元素通过lambda函数转换为tuple类型可序列
def dedupe(items, key=None): seen = set() for item in items: val = item if key is None else key(item) if val not in seen: yield item seen.add(val)
输出
>>> a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}] >>> list(dedupe(a, key=lambda d: (d['x'],d['y']))) [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}] >>> list(dedupe(a, key=lambda d: d['x'])) [{'x': 1, 'y': 2}, {'x': 2, 'y': 4}] >>>