from itertools import takewhile, islice
def groups(l, keys, i, n):
# lambda x: x != 0 -> take elements until we encounter any 0
tk = takewhile(lambda x: x != i, l)
while True:
d = dict(zip(keys, islice(tk, n)))
if len(d) == n: # make sure we have n keys in the dict
yield d
else:
break
keys = ['gold', 'silver', 'bronze']
print(list(groups(l,keys,0,3)))
[{'bronze': 3, 'gold': 1, 'silver': 2}, {'bronze': 6, 'gold': 4, 'silver': 5}]
takewhile
创建一个迭代器,只要谓词为真,它就会从可迭代对象中返回元素。
所以我们只取元素直到我们遇到的第一个 i,d = islice(tk,n) 使用 islice 从我们的 takewhile 对象中取一个 n 长度切片,然后我们从传入的键创建一个字典,创建dict 一次消耗n 元素,因此每次调用它时我们都会移动到接下来的三个元素。如果 takewhile 对象的长度不是n 的倍数,那么我们最后会有一个小于n 大小的dict,所以if len(d) == n: 会捕捉到它并打破循环,所以奇怪的是长度字典或空字典将终止while。
如果您允许使用少于三个键的字典:
from itertools import takewhile, islice,chain
def groups(l, keys, i, n):
tk = takewhile(lambda x: x != i, l)
return (dict(zip(keys, chain(islice(tk, n - 1),(i,)))) for i in tk)
输出:
In [5]: l = [1, 2, 3, 4, 5, 6, 7, 11, 6, 9, 0, 2]
In [6]: list(groups(l,['gold', 'silver', 'bronze'],0,3))
Out[6]:
[{'bronze': 1, 'gold': 2, 'silver': 3},
{'bronze': 4, 'gold': 5, 'silver': 6},
{'bronze': 7, 'gold': 11, 'silver': 6},
{'gold': 9}]
islice(tk, n - 1) 从我们的 takewhile 对象 len n - 1 中获取一个切片,我们将它和i 链接起来,所以我们每次都得到n 元素。
或者使用filter过滤掉少于3个key的dict:
def groups(l, keys, i, n):
tk = takewhile(lambda x: x != i, l)
return filter(lambda x: len(x) == n, (dict(zip(keys, chain(islice(tk, n - 1),(i,))))
for i in tk))
删除较短的字典:
In [8]: list(groups(l,['gold', 'silver', 'bronze'],0,3))
Out[8]:
[{'bronze': 1, 'gold': 2, 'silver': 3},
{'bronze': 4, 'gold': 5, 'silver': 6},
{'bronze': 7, 'gold': 11, 'silver': 6}]
这与之前的相同,我们只是从末尾过滤任何可能的奇数长度字典。对于 python2 使用 itertools.ifilter 而不是过滤器。