Python itertools——高效迭代

PS:本文Python 3.6.4,更高Python版本有更豐富的功能

Python內置庫itertools可以高效創建一系列迭代器,使代碼更簡潔。





引入包

import operator
from itertools import *
from collections import *

累計accumulate

功能:對前後項進行運算,默認爲加法

原型:accumulate(iterable, func=operator.add)


xn=i=1ni=1+2+...+nx_n=\sum_{i=1}^{n}{i}=1+2+...+n

list(accumulate([1,2,3,4,5]))  # 默認累計
#[1, 3, 6, 10, 15]

xn=i=1ni=1×2××nx_n=\prod_{i=1}^n{i}=1\times 2\times …\times n

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)




推薦閱讀:Python可迭代對象、迭代器和生成器的區別


參考文獻

  1. itertools — Functions creating iterators for efficient looping
  2. itertools - 廖雪峯的官方網站
  3. Python過濾元素哪家強?pandas、filter、filterfalse還是dropwhile
  4. Python中的分組函數(groupby、itertools)
  5. Python標準庫之itertools庫的使用方法
  6. 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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章