PS:本文Python 3.6.4,更高Python版本有更豐富的功能
Python內置庫itertools可以高效創建一系列迭代器,使代碼更簡潔。
文章目錄
- 累計accumulate
- 串聯chain
- 組合combinations
- 排列permutations
- 笛卡兒積product
- 壓縮compress
- 連續值count
- 無限循環cycle
- 拋棄dropwhile
- 取真takewhile
- 過濾假值filterfalse
- 分組groupby
- 分組islice
- 重複repeat
- 分裂tee
- 加強映射starmap
- 加強打包zip_longest
- 實例
- 1. 取前n個元素,返回list
- 2. 前插,返回迭代器
- 3. 連續應用函數,返回迭代器
- 4. 取後n個元素,返回迭代器
- 5. 推進迭代器
- 6. 取第n個元素,沒有的話返回默認值
- 7. 是否所有值都相等
- 8. 檢驗結果爲True的次數
- 9. 先返回可迭代對象再無限填充None
- 10. 循環可迭代對象n次
- 11. 兩兩組合
- 12. 分組器,將數據收集到長度爲n的塊中
- 13. 輪詢
- 14. 根據檢測結果劃分兩部分
- 15. 組合成元組
- 16. 列出唯一的元素,可設過濾
- 17. 一旦不同,列出元素
- 18. 重複調用函數,直到引發異常
- 19. 壓平一層嵌套list
- 參考文獻
- 彙總
引入包
import operator
from itertools import *
from collections import *
累計accumulate
功能:對前後項進行運算,默認爲加法
原型:accumulate(iterable, func=operator.add)
list(accumulate([1,2,3,4,5])) # 默認累計
#[1, 3, 6, 10, 15]
list(accumulate([1,2,3,4,5], func=operator.mul)) # 累乘
#[1, 2, 6, 24, 120]
list(accumulate([3,2,1,4,5], func=max)) # 求當前最大值
#[3, 3, 3, 4, 5]
list(accumulate([1,2,3,4,5], func=lambda old,new: 2*old+new)) # 自定義累計方式
#[1, 4, 11, 26, 57]
只要最終結果functools.reduce()
from functools import reduce
print(reduce(lambda x, y: x + y, [1,2,3,4,5]))
print(reduce(operator.mul, [1,2,3,4,5]))
print(reduce(max, [3,2,1,4,5]))
print(reduce(lambda old,new: 2*old+new, [1,2,3,4,5]))
# 15
# 120
# 5
# 57
串聯chain
功能:解開可迭代對象的最外層
原型:chain(*iterables)
list(chain([1,2], (3,4), {5,6}, {'a':'a'}, [[7,8]])) #內置可迭代對象:list、tuple、dict、set、str
# [1, 2, 3, 4, 5, 6, 'a', [7, 8]]
class A:
def __init__(self, n):
self.items = list(range(n))
def __iter__(self):
return iter(self.items)
a = A(n=10)
list(chain(a)) # 自定義可迭代對象也行
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
組合combinations
功能:返回長度爲r的子序列
原型:combinations(iterable, r)
list(combinations([0,1,2,3,4], 3))
# [(0, 1, 2),
# (0, 1, 3),
# (0, 1, 4),
# (0, 2, 3),
# (0, 2, 4),
# (0, 3, 4),
# (1, 2, 3),
# (1, 2, 4),
# (1, 3, 4),
# (2, 3, 4)]
list(map(''.join,combinations('ABCD', 2)))
# ['AB', 'AC', 'AD', 'BC', 'BD', 'CD']
list(map(''.join, combinations_with_replacement('ABCD', 2))) # 允許重複出現
# ['AA', 'AB', 'AC', 'AD', 'BB', 'BC', 'BD', 'CC', 'CD', 'DD']
排列permutations
功能:類似組合combinations,返回長度爲r的排列
原型:permutations(iterable, r=None)
list(permutations([1,2,3], 2))
# [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
list(map(''.join, permutations('ABCD', 2)))
# ['AB', 'AC', 'AD', 'BA', 'BC', 'BD', 'CA', 'CB', 'CD', 'DA', 'DB', 'DC']
笛卡兒積product
功能:返回可迭代對象的笛卡兒積
原型:product(*iterables, repeat=1)
list(map(''.join, product('ABCD', '123')))
# ['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3', 'D1', 'D2', 'D3']
重複次數爲3,相當於list(product([0,1], [0,1], [0,1]))
list(product([0,1], repeat=3))
# [(0, 0, 0),
# (0, 0, 1),
# (0, 1, 0),
# (0, 1, 1),
# (1, 0, 0),
# (1, 0, 1),
# (1, 1, 0),
# (1, 1, 1)]
壓縮compress
功能:返回data對應selectors爲True的元素
原型:compress(data, selectors)
list(compress('ABCDEF', [1,1,1,0,0,0]))
list(compress('ABCDEF', [True,True,True,False,False,False]))
# ['A', 'B', 'C']
相當於
temp = []
data = 'ABCDEF'
selectors = [1,1,1,0,0,0]
for d, s in zip(data, selectors):
if s:
temp.append(d)
print(temp)
# ['A', 'B', 'C']
連續值count
功能:從start值開始,返回均勻step間隔的值
原型:count(start=0, step=1)
從10開始逐漸加1
a = count(10)
temp = []
for i in range(5):
temp.append(next(a))
print(temp)
# [10, 11, 12, 13, 14]
從0開始逐漸加2.5
temp = []
a = count(start=0, step=2.5)
for i in range(5):
temp.append(next(a))
print(temp)
# [0, 2.5, 5.0, 7.5, 10.0]
無限循環cycle
功能:無限循環可迭代對象
原型:cycle(iterable)
temp = []
a = cycle([1,2,3])
for i in range(10):
temp.append(next(a))
print(temp)
# [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
拋棄dropwhile
功能:拋棄predicate爲True的元素,一旦爲False則返回餘下
原型:dropwhile(predicate, iterable)
list(dropwhile(lambda x: x<3, [1,2,3,4,5])) #拋棄小於3的元素
# [3, 4, 5]
list(dropwhile(lambda x: x>3, [1,2,3,4,5])) #拋棄大於3的元素,一開始爲False則返回餘下
# [1, 2, 3, 4, 5]
與filter()
相反
list(filter(lambda x: x>=3, [1,2,3,4,5])) #保留大於等於3的元素
# [3, 4, 5]
取真takewhile
功能:保留predicate爲True的元素,一旦爲False則停止
原型:takewhile(predicate, iterable)
list(takewhile(lambda x: x<3, [1,2,3,4,5]))
# [1, 2]
list(takewhile(lambda x: x>3, [1,2,3,4,5]))
# []
過濾假值filterfalse
功能:與filter相反,與dropwhile類似,保留false的值
原型:filterfalse(predicate, iterable)
list(filterfalse(lambda x: x<3, [1,2,3,4,5]))
# [3, 4, 5]
分組groupby
功能:返回iterable中連續的值
原型:groupby(iterable, key=None)
備註:不同於SQL的groupby,必須是連續值
[k for k, g in groupby('AAAABBBCCDAABBB')]
# ['A', 'B', 'C', 'D', 'A', 'B']
[list(g) for k, g in groupby('AAAABBBCCDAABBB')]
# [['A', 'A', 'A', 'A'],
# ['B', 'B', 'B'],
# ['C', 'C'],
# ['D'],
# ['A', 'A'],
# ['B', 'B', 'B']]
d = [{'name': 'a', 'country': 'China'},
{'name': 'b', 'country': 'China'},
{'name': 'c', 'country': 'JP'},
{'name': 'd', 'country': 'USA'},
{'name': 'e', 'country': 'USA'},
{'name': 'f', 'country': 'China'}]
[list(g) for k, g in groupby(d, key=lambda x:x['country'])]
# [[{'name': 'a', 'country': 'China'}, {'name': 'b', 'country': 'China'}],
# [{'name': 'c', 'country': 'JP'}],
# [{'name': 'd', 'country': 'USA'}, {'name': 'e', 'country': 'USA'}],
# [{'name': 'f', 'country': 'China'}]]
分組islice
功能:類似切片,但參數不允許爲負值
原型:islice(iterable, stop)
或islice(iterable, start, stop[, step])
list(islice('ABCDEFG', 2)) # 取0-2
# ['A', 'B']
list(islice('ABCDEFG', 2, 4)) # 取2-4
# ['C', 'D']
list(islice('ABCDEFG', 2, None)) # 取2-末尾
# ['C', 'D', 'E', 'F', 'G']
list(islice('ABCDEFG', 0, None, 2)) # 取0-末尾,間隔爲2
# ['A', 'C', 'E', 'G']
重複repeat
功能:不斷重複object
原型:repeat(object, times=None)
list(repeat(10, 3)) # 將10重複3次
# [10, 10, 10]
list(map(pow, range(10), repeat(2))) # 求0-9的平方,爲map提供常量流
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
分裂tee
功能:返回n個獨立的迭代器
原型:tee(iterable, n=2)
list(map(list, tee([1,2,3,4,5], 2)))
# [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
加強映射starmap
功能:類似map,根據函數對序列做映射
原型:starmap(function, iterable)
list(starmap(pow, [(2,5), (3,2), (10,3)])) # 2的5次方
# [32, 9, 1000]
加強打包zip_longest
功能:與zip類似,若長度未對齊會用fillvalue填充
原型:zip_longest(*iterables, fillvalue=None)
list(zip_longest('ABCD', 'xy', fillvalue='-'))
# [('A', 'x'), ('B', 'y'), ('C', '-'), ('D', '-')]
實例
1. 取前n個元素,返回list
def take(iterable, n):
'''取前n個元素,返回list
:param iterable: 可迭代對象
:param n: 元素數量
:rtype: list
>>> take(range(10), 5)
[0, 1, 2, 3, 4]
>>> take({'a':1, 'b':2, 'c':3}, 2)
['a', 'b']
'''
return list(islice(iterable, n))
2. 前插,返回迭代器
def prepend(iterator, value):
'''前插
:param iterator: 迭代器
:param value: 前插元素
:rtype: iterator
>>> list(prepend([2, 3, 4], 1))
[1, 2, 3, 4]
'''
return chain([value], iterator)
3. 連續應用函數,返回迭代器
def tabulate(function, start=0, step=1):
'''連續應用函數,返回迭代器
:param function: 執行的函數
:param start: 起始值
:param step: 步長
:rtype: Iterator
>>> it = tabulate(lambda x: x**2)
>>> result = []
>>> for i, j in enumerate(it):
... if i == 10:
... break
... result.append(j)
>>> result
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
'''
return map(function, count(start, step))
4. 取後n個元素,返回迭代器
def tail(iterable, n):
'''取後n個元素,返回迭代器
:param iterable: 可迭代對象
:param n: 元素數量
:rtype: Iterator
>>> list(tail(range(10), 5))
[5, 6, 7, 8, 9]
>>> list(tail({'a': 1, 'b': 2, 'c': 3}, 2))
['b', 'c']
'''
return iter(deque(iterable, maxlen=n))
5. 推進迭代器
def consume(iterator, n=None):
'''推進迭代器
:param iterator: 迭代器
:param n: 元素數量,默認None全部消費
:return: None
>>> l = iter([0, 1, 2, 3, 4])
>>> consume(l, n=3)
>>> list(l)
[3, 4]
'''
if n:
next(islice(iterator, n, n), None)
else:
deque(iterator, maxlen=0)
6. 取第n個元素,沒有的話返回默認值
def nth(iterable, n, default=None):
'''取第n個元素,沒有的話返回默認值
:param iterable: 可迭代對象
:param n: 第n個元素
:param default: 取不到時返回的默認值,默認爲None
>>> nth('Hello', 1)
'e'
>>> nth([0, 1, 2, 3], 5, default='absence')
'absence'
'''
return next(islice(iterable, n, None), default)
7. 是否所有值都相等
def all_equal(iterable):
'''是否所有值都相等
:param iterable: 可迭代對象
:return: True or False
>>> all_equal('AAAAAA')
True
>>> all_equal('AAAABBBCCDAABBB')
False
'''
g = groupby(iterable)
return next(g, True) and not next(g, False)
8. 檢驗結果爲True的次數
def quantify(iterable, function=bool):
'''檢測結果爲True的次數
:param iterable: 可迭代對象
:param function: 檢測方法,默認爲bool
:rtype: int
>>> quantify([1, 0, 0, 1, 0])
2
>>> quantify('AAAaa', str.isupper)
3
'''
return sum(map(function, iterable))
9. 先返回可迭代對象再無限填充None
def padnone(iterable):
'''先返回可迭代對象再無限填充None
:param iterable: 可迭代對象
:rtype: iterator
>>> it = padnone([0, 1, 2])
>>> result = []
>>> for i, j in enumerate(it):
... if i == 5:
... break
... result.append(j)
>>> result
[0, 1, 2, None, None]
'''
return chain(iterable, repeat(None))
10. 循環可迭代對象n次
def ncycles(iterable, n):
'''循環可迭代對象n次
:param iterable: 可迭代對象
:param n: 循環次數
:rtype: iterator
>>> list(ncycles([0, 1, 2], n=3))
[0, 1, 2, 0, 1, 2, 0, 1, 2]
'''
return chain.from_iterable(repeat(tuple(iterable), n))
11. 兩兩組合
def pairwise(iterable):
'''兩兩組合
:param iterable: 可迭代對象
:rtype: iterator
>>> list(pairwise([0, 1, 2, 3]))
[(0, 1), (1, 2), (2, 3)]
'''
a, b = tee(iterable)
next(b, None)
return zip(a, b)
12. 分組器,將數據收集到長度爲n的塊中
def grouper(iterable, n, fillvalue=None):
'''分組器,將數據收集到長度爲n的塊中
:param iterable: 可迭代對象
:param n: 每個塊的長度
:param fillvalue: 填充值
:rtype: iterator
>>> list(grouper('ABCDEFG', 3, 'x'))
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G', 'x', 'x')]
'''
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)
13. 輪詢
def roundrobin(*iterables):
'''輪詢
:param iterables: 一個或多個可迭代對象
:rtype: iterator
>>> list(roundrobin('ABC', 'D', 'EF'))
['A', 'D', 'E', 'B', 'F', 'C']
'''
num_active = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while num_active:
try:
for next in nexts:
yield next()
except StopIteration:
num_active -= 1
nexts = cycle(islice(nexts, num_active))
14. 根據檢測結果劃分兩部分
def partition(iterable, function=bool):
'''根據檢測結果劃分兩部分
:param iterable: 可迭代對象
:param function: 檢測方法,默認爲bool
:rtype: Tuple[Iterator, Iterator]
>>> list(map(list, partition([0, 1, 0, 1, 0])))
[[1, 1], [0, 0, 0]]
>>> list(map(list, partition(range(10), lambda x: x%2==0)))
[[0, 2, 4, 6, 8], [1, 3, 5, 7, 9]]
'''
t1, t2 = tee(iterable)
return filter(function, t1), filterfalse(function, t2)
15. 組合成元組
def powerset(iterable):
'''組合成元組
:param iterable: 可迭代對象
:rtype: iterator
>>> list(powerset([1,2,3]))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
'''
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
16. 列出唯一的元素,可設過濾
def unique_everseen(iterable, key=None):
'''列出唯一的元素,可設過濾
:param iterable: 可迭代對象
:param key: 過濾條件,默認不過濾
:rtype: iterator
>>> list(unique_everseen('AABBCCDDABCD'))
['A', 'B', 'C', 'D']
>>> list(unique_everseen('AaBbCcDd', str.lower))
['A', 'B', 'C', 'D']
'''
seen = set()
seen_add = seen.add
if key is None:
for element in filterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
17. 一旦不同,列出元素
def unique_justseen(iterable, key=None):
'''一旦不同,列出元素
:param iterable: 可迭代對象
:param key: 過濾條件,默認不過濾
:rtype: iterator
>>> list(unique_justseen('AABBCCDDABCD'))
['A', 'B', 'C', 'D', 'A', 'B', 'C', 'D']
>>> list(unique_justseen('AaBbCcDd', str.lower))
['A', 'B', 'C', 'D']
'''
return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
18. 重複調用函數,直到引發異常
def iter_except(func, exception, first=None):
'''重複調用函數,直到引發異常
:param func: 調用的函數
:param exception: 引發的異常
:param first: 初始化函數,如數據庫
:rtype: iterator
>>> s = {0, 1, 2, 3, 4}
>>> list(iter_except(s.pop, KeyError))
[0, 1, 2, 3, 4]
'''
try:
if first is not None:
yield first()
while True:
yield func()
except exception:
pass
19. 壓平一層嵌套list
def flatten(list_of_lists):
'''壓平一層嵌套list
:param list_of_lists: 嵌套list
:rtype: iterator
>>> list(flatten([[1], [2], [3]]))
[1, 2, 3]
'''
return chain.from_iterable(list_of_lists)
參考文獻
- itertools — Functions creating iterators for efficient looping
- itertools - 廖雪峯的官方網站
- Python過濾元素哪家強?pandas、filter、filterfalse還是dropwhile
- Python中的分組函數(groupby、itertools)
- Python標準庫之itertools庫的使用方法
- Python可迭代對象、迭代器和生成器的區別
彙總
from itertools import *
from collections import *
from operator import itemgetter
def take(iterable, n):
'''取前n個元素,返回list
:param iterable: 可迭代對象
:param n: 元素數量
:rtype: list
>>> take(range(10), 5)
[0, 1, 2, 3, 4]
>>> take({'a':1, 'b':2, 'c':3}, 2)
['a', 'b']
'''
return list(islice(iterable, n))
def prepend(iterator, value):
'''前插,返回迭代器
:param iterator: 迭代器
:param value: 前插元素
:rtype: iterator
>>> list(prepend([2, 3, 4], 1))
[1, 2, 3, 4]
'''
return chain([value], iterator)
def tabulate(function, start=0, step=1):
'''連續應用函數,返回迭代器
:param function: 執行的函數
:param start: 起始值
:param step: 步長
:rtype: Iterator
>>> it = tabulate(lambda x: x**2)
>>> result = []
>>> for i, j in enumerate(it):
... if i == 10:
... break
... result.append(j)
>>> result
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
'''
return map(function, count(start, step))
def tail(iterable, n):
'''取後n個元素,返回迭代器
:param iterable: 可迭代對象
:param n: 元素數量
:rtype: Iterator
>>> list(tail(range(10), 5))
[5, 6, 7, 8, 9]
>>> list(tail({'a': 1, 'b': 2, 'c': 3}, 2))
['b', 'c']
'''
return iter(deque(iterable, maxlen=n))
def consume(iterator, n=None):
'''推進迭代器
:param iterator: 迭代器
:param n: 元素數量,默認None全部消費
:return: None
>>> l = iter([0, 1, 2, 3, 4])
>>> consume(l, n=3)
>>> list(l)
[3, 4]
'''
if n:
next(islice(iterator, n, n), None)
else:
deque(iterator, maxlen=0)
def nth(iterable, n, default=None):
'''取第n個元素,沒有的話返回默認值
:param iterable: 可迭代對象
:param n: 第n個元素
:param default: 取不到時返回的默認值,默認爲None
>>> nth('Hello', 1)
'e'
>>> nth([0, 1, 2, 3], 5, default='absence')
'absence'
'''
return next(islice(iterable, n, None), default)
def all_equal(iterable):
'''是否所有值都相等
:param iterable: 可迭代對象
:return: True or False
>>> all_equal('AAAAAA')
True
>>> all_equal('AAAABBBCCDAABBB')
False
'''
g = groupby(iterable)
return next(g, True) and not next(g, False)
def quantify(iterable, function=bool):
'''檢測結果爲True的次數
:param iterable: 可迭代對象
:param function: 檢測方法,默認爲bool
:rtype: int
>>> quantify([1, 0, 0, 1, 0])
2
>>> quantify('AAAaa', str.isupper)
3
'''
return sum(map(function, iterable))
def padnone(iterable):
'''先返回可迭代對象再無限填充None
:param iterable: 可迭代對象
:rtype: iterator
>>> it = padnone([0, 1, 2])
>>> result = []
>>> for i, j in enumerate(it):
... if i == 5:
... break
... result.append(j)
>>> result
[0, 1, 2, None, None]
'''
return chain(iterable, repeat(None))
def ncycles(iterable, n):
'''循環可迭代對象n次
:param iterable: 可迭代對象
:param n: 循環次數
:rtype: iterator
>>> list(ncycles([0, 1, 2], n=3))
[0, 1, 2, 0, 1, 2, 0, 1, 2]
'''
return chain.from_iterable(repeat(tuple(iterable), n))
def pairwise(iterable):
'''兩兩組合
:param iterable: 可迭代對象
:rtype: iterator
>>> list(pairwise([0, 1, 2, 3]))
[(0, 1), (1, 2), (2, 3)]
'''
a, b = tee(iterable)
next(b, None)
return zip(a, b)
def grouper(iterable, n, fillvalue=None):
'''分組器,將數據收集到長度爲n的塊中
:param iterable: 可迭代對象
:param n: 每個塊的長度
:param fillvalue: 填充值
:rtype: iterator
>>> list(grouper('ABCDEFG', 3, 'x'))
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G', 'x', 'x')]
'''
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)
def roundrobin(*iterables):
'''輪詢
:param iterables: 一個或多個可迭代對象
:rtype: iterator
>>> list(roundrobin('ABC', 'D', 'EF'))
['A', 'D', 'E', 'B', 'F', 'C']
'''
num_active = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while num_active:
try:
for next in nexts:
yield next()
except StopIteration:
num_active -= 1
nexts = cycle(islice(nexts, num_active))
def partition(iterable, function=bool):
'''根據檢測結果劃分兩部分
:param iterable: 可迭代對象
:param function: 檢測方法,默認爲bool
:rtype: Tuple[Iterator, Iterator]
>>> list(map(list, partition([0, 1, 0, 1, 0])))
[[1, 1], [0, 0, 0]]
>>> list(map(list, partition(range(10), lambda x: x%2==0)))
[[0, 2, 4, 6, 8], [1, 3, 5, 7, 9]]
'''
t1, t2 = tee(iterable)
return filter(function, t1), filterfalse(function, t2)
def powerset(iterable):
'''組合成元組
:param iterable: 可迭代對象
:rtype: iterator
>>> list(powerset([1,2,3]))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
'''
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))
def unique_everseen(iterable, key=None):
'''列出唯一的元素,可設過濾
:param iterable: 可迭代對象
:param key: 過濾條件,默認不過濾
:rtype: iterator
>>> list(unique_everseen('AABBCCDDABCD'))
['A', 'B', 'C', 'D']
>>> list(unique_everseen('AaBbCcDd', str.lower))
['A', 'B', 'C', 'D']
'''
seen = set()
seen_add = seen.add
if key is None:
for element in filterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
def unique_justseen(iterable, key=None):
'''一旦不同,列出元素
:param iterable: 可迭代對象
:param key: 過濾條件,默認不過濾
:rtype: iterator
>>> list(unique_justseen('AABBCCDDABCD'))
['A', 'B', 'C', 'D', 'A', 'B', 'C', 'D']
>>> list(unique_justseen('AaBbCcDd', str.lower))
['A', 'B', 'C', 'D']
'''
return map(next, map(itemgetter(1), groupby(iterable, key)))
def iter_except(func, exception, first=None):
'''重複調用函數,直到引發異常
:param func: 調用的函數
:param exception: 引發的異常
:param first: 初始化函數,如數據庫
:rtype: iterator
>>> s = {0, 1, 2, 3, 4}
>>> list(iter_except(s.pop, KeyError))
[0, 1, 2, 3, 4]
'''
try:
if first is not None:
yield first()
while True:
yield func()
except exception:
pass