ITERTOOLS模組小結

Kivinsae發表於2019-03-07

ITERTOOLS是一個高效迴圈的迭代函式集合。正好在最近的應用的時候用的比較多,網上幾個比較詳細的介紹帖子要麼寫的抽象,要麼例子不夠簡潔。就大概整理了一下,搬運成分偏少。反正不重複造輪子是一個比較pythonic的原則,所以有空就分享一下。不過個人推薦有空還是可以看一下這些內建函式本身的實現原始碼,都非常簡潔。

以及,這東西遇到某些沒有限制的leetcode題目不就是秒殺嗎,更別說生產環境的很多小資料處理需求了。做碼農不偷懶那還是人嗎。

一、組成

itertools主要來分為三類函式,分別為無限迭代器、輸入序列迭代器、組合生成器,我們下面開始具體講解。

二、無限迭代器

1、Itertools.count(start=0, step=1) 建立一個迭代物件,生成從start開始的連續整數,步長為step。 如果省略了start則預設從0開始,步長預設為1 如果超過了sys.maxint,則會移除並且從-sys.maxint-1開始計數。

    例:
    from itertools import *
    for i in izip(count(2,6), ['a', 'b', 'c']):
    print i
    輸出為:
    (2, 'a')
    (8, 'b')
    (14, 'c')
複製程式碼

2、Itertools.cycle(iterable) 建立一個迭代物件,對於輸入的iterable的元素反覆執行迴圈操作,內部生成iterable中的元素的一個副本,這個副本用來返回迴圈中的重複項。

    例:
    from itertools import *
    i = 0
    for item in cycle(['a', 'b', 'c']):
        i += 1
        if i == 10:
            break
        print (i, item)
    輸出為:
    (1, 'a')
    (2, 'b')
    (3, 'c')
    (4, 'a')    
    (5, 'b')
    (6, 'c')
    (7, 'a')
    (8, 'b')
    (9, 'c')
複製程式碼

3、Itertools.repeat(object[, times]) 建立一個迭代器,重複生成object,如果沒有設定times,則會無線生成物件。

    例:
    from itertools import *
    for i in repeat('kivinsae', 5):
        print I
    輸出為:
    kivinsae
    kivinsae
    kivinsae
    kivinsae
    kivinsae
複製程式碼

三、輸入序列迭代器

0、itertools.accumulate(*iterables) 這個函式簡單來說就是一個累加器,不停對列表或者迭代器進行累加操作(這裡指每項累加)。

 例:
    from itertools import *
    x = itertools.accumulate(range(10))
    print(list(x))
    輸出為:
    [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
複製程式碼

1、itertools.chain(*iterables) 把多個迭代器作為引數,但是隻會返回單個迭代器。產生所有引數迭代器的內容,卻好似來自於一個單一的序列。簡單了講就是連線多個【列表】或者【迭代器】。

    例:
    from itertools import *
    for i in chain(['p','x','e'], ['scp', 'nmb', 'balenciaga']):
        print I
    輸出為:
    p
    x
    e
    scp
    nmb
    balenciaga
複製程式碼

2、itertools.compress(data,selectors) 具體來說compress提供了一個對於原始資料的篩選功能,具體條件可以設定的非常複雜,所以下面只列出相關的定義程式碼來解釋。不過簡單來理解,就是說按照真值表進行元素篩選而已。

    實現過程:
    def compress(data, selectors):
        # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
        return (d for d, s in izip(data, selectors) if s)    

    例:
    from itertools import compress
    list(compress('ABCDEF', [1, 1, 0, 1, 0, 1]))
    輸出為:
    ['A', 'B', 'D', 'F']
複製程式碼

3、itertools.dropwhile(predicate,iterable) dropwhile作用是建立一個迭代器,只要是函式predicate(item)為True,則丟掉iterable中的項,但是如果predicate返回的是False,則生成iterable中的項和所有的後續項。 具體來說就是,在條件為False之後的第一次,就返回迭代器中剩餘的所有項。在這個函式表示式裡面iterable的值會按索引一個個作為predicate的引數進行計算。 簡單來說其實就是按照真值函式丟棄掉列表和迭代器前面的元素。

    例:
    from itertools import *
    def should_drop(x):
        print 'Testing:', x
        return (x<1)
    for i in dropwhile(should_drop, [ -1, 0, 1, 2, 3, 4, 1, -2 ]):
        print 'Yielding:', i
    輸出為:
    Testing: -1
    Testing: 0
    Testing: 1
    Yielding: 1
    Yielding: 2
    Yielding: 3
    Yielding: 4
    Yielding: 1
    Yielding: -2
複製程式碼

4、itertools.groupby(iterable[,key]) 返回一個集合的迭代器,集合內是按照key進行分組後的值。 如果iterable在多次連續的迭代中生成了同一項,則會定義一個組,如果對這個函式應用一個分類列表,那麼分組會定義這個列表中所有的唯一項,key是一個函式並應用於每一項。如果這個函式有返回值,則這個值會用於後續的項,而不是和該項本身進行比較。這個函式返回的迭代器生成元素(key,group),key是分組的鍵值,group是迭代器,從而生成組成這個組的所有專案。 具體來說實現過程和示例如下:

    實現過程:
    class groupby(object):
        # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
        # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
        def __init__(self, iterable, key=None):
            if key is None:
                key = lambda x: x
            self.keyfunc = key
            self.it = iter(iterable)
            self.tgtkey = self.currkey = self.currvalue = object()
        def __iter__(self):
            return self
        def next(self):
            while self.currkey == self.tgtkey:
                self.currvalue = next(self.it)    # Exit on StopIteration
                self.currkey = self.keyfunc(self.currvalue)
            self.tgtkey = self.currkey
            return (self.currkey, self._grouper(self.tgtkey))
        def _grouper(self, tgtkey):
            while self.currkey == tgtkey:
                yield self.currvalue
                self.currvalue = next(self.it)    # Exit on StopIteration
                self.currkey = self.keyfunc(self.currvalue)

    例:
    from itertools import *
    a = ['aa', 'ab', 'abc', 'bcd', 'abcde']
    for i, k in groupby(a, len):
        print i, list(k)
    輸出為:
    2 ['aa', 'ab']
    3 ['abc', 'bcd']
    5 ['abcde']
複製程式碼

5、itertools.ifilter(predicate,iterable) 本函式返回一個迭代器,類似於針對於列表的函式filter(),但是隻包括測試函式返回True時候的值。和dropwhile()作用不同。 函式建立一個迭代器,只生成predicate(iterable)為True的項,簡單來說就是返回iterable中所有計算後為True的項。如果是非True則進行之後的其他操作。

    例:
    from itertools import *
    def check_item(x):
        print 'Testing:', x
        return (x<1)
    for i in ifilter(check_item, [ -1, 0, 1, 2, 3, 4, 1, -2 ]):
        print 'Yielding:', i
    輸出為:
    Testing: -1
    Yielding: -1
    Testing: 0
    Yielding: 0
    Testing: 1
    Testing: 2
    Testing: 3
    Testing: 4
    Testing: 1
    Testing: -2
    Yielding: -2
複製程式碼

6、itertools.ifilterfalse(predicate,iterable) 本函式和上面的ifilter一樣,唯一的區別是隻有當predicate(iterable)為False時候才進行predicate的輸出。

    例:
    from itertools import *
    def check_item(x):
        print 'Testing:', x
        return (x<1)
    for i in ifilterfalse(check_item, [ -1, 0, 1, 2, 3, 4, 1, -2 ]):
        print 'Yielding:', I
    輸出為:
    Testing: -1
    Testing: 0
    Testing: 1
    Yielding: 1
    Testing: 2
    Yielding: 2
    Testing: 3
    Yielding: 3
    Testing: 4
    Yielding: 4
    Testing: 1
    Yielding: 1
    Testing: -2
複製程式碼

7、itertools.islice(iterable,stop) 簡單來說這個函式,就是對於一個迭代物件iterable,設定一個特定的切片/選取/擷取規則,然後最後輸出一個特定的新的迭代物件的過程。這個stop實際上代表一個三元陣列,也就是start,stop,step。如果start省略,預設從索引0開始;如果step被省略,則預設步長為1;stop不能被省略。本質就是一個切片工具。

    例:
    from itertools import *
    print 'Stop at 5:'
    for i in islice(count(), 5):
        print i
    
    print 'Start at 5, Stop at 10:'
    for i in islice(count(), 5, 10):
        print i
    print 'By tens to 100:'
    for i in islice(count(), 0, 100, 10):
        print I
    輸出為:
    Stop at 5:
    0
    1
    2
    3
    4
    Start at 5, Stop at 10:
    5
    6
    7
    8
    9
    By tens to 100:
    0
    10
    20
    30
    40
    50
    60
    70
    80
    90
複製程式碼

8、itertools.imap(function,*iterable) 本函式建立一個迭代器,作用函式為function1,function2,function3…,對應的變數來自迭代器iterable1,iterable2,iterable3…。然後返回一個(f1,f2,f3…)形式的元組。只要其中一個迭代器不再生成值,這個函式就會停止。所以要處理好None的情況,用一下替代輸出之類的方法。

    例:
    from itertools import *
    print 'Doubles:'
    for i in imap(lambda x:2*x, xrange(5)):
        print i
    print 'Multiples:'
    for i in imap(lambda x,y:(x, y, x*y), xrange(5), xrange(5,10)):
        print '%d * %d = %d' % I
    輸出為:
    Doubles:
    0
    2
    4
    6
    8
    Multiples:
    0 * 5 = 0
    1 * 6 = 6
    2 * 7 = 14
    3 * 8 = 24
    4 * 9 = 36
複製程式碼

9、itertools.starmap(function,iterable) 本函式建立一個函式,其中內呼叫的function(*item),item來自於iterable。只有當迭代物件iterable生成的項適合這個函式的呼叫形式的時候,starmap才會有效。

    例:
    from itertools import *
    values = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]
    for i in starmap(lambda x,y:(x, y, x*y), values):
        print '%d * %d = %d' % I
    輸出為:
    0 * 5 = 0
    1 * 6 = 6
    2 * 7 = 14
    3 * 8 = 24
    4 * 9 = 36
複製程式碼

10、itertools.tee(iterable[,n=2]) 這個函式會返回若干個基於某個原始輸入的獨立迭代器。類似於Linux系統上的tee指令。如果不特地制定n的話,函式會預設是2。tee括號裡面最好使用標準輸入,而不是原始迭代器。不然會在某些快取過程中出現異常。

    例:
    from itertools import *
    r = islice(count(), 5)
    i1, i2 = tee(r)
    for i in i1:
        print 'i1:', i
    for i in i2:
        print 'i2:', I
    輸出為:
    i1: 0
    i1: 1
    i1: 2
    i1: 3
    i1: 4
    i2: 0
    i2: 1
    i2: 2
    i2: 3
    i2: 4
複製程式碼

11、itertools.takewhile(predicate,iterable) 這個函式和dropwhile剛好相反,只要predicate計算後為False,迭代過程立刻停止。

    例:
    from itertools import *
    def should_take(x):
        print 'Testing:', x
        return (x<2)
    for i in takewhile(should_take, [ -1, 0, 1, 2, 3, 4, 1, -2 ]):
        print 'Yielding:', I
    輸出為:
    Testing: -1
    Yielding: -1
    Testing: 0
    Yielding: 0
    Testing: 1
    Yielding: 1
    Testing: 2
複製程式碼

12、itertools.izip( *iterables) 這個函式返回一個合併多個迭代器,成為一個元組的迭代物件。類似於內建函式zip,但返回的是迭代物件而非列表。 建立一個迭代物件,生成元組(i1,i2,i3…)分別來自於i1,i2,i3…,只要提供的某個迭代器不在生成值,函式就會立刻停止。

    例:
    from itertools import *
    for i in izip([1, 2, 3], ['a', 'b', 'c']):
        print I
    輸出為:
    (1, 'a')
    (2, 'b')
    (3, 'c')
複製程式碼

13、itertools.izip_longest(*iterable[,fillvalue]) 本函式和izip雷同,但是區別在於不會停止,會把所有輸入的迭代物件全部耗盡為止,對於引數不匹配的項,會用None代替。非常容易理解。

    例:
    from itertools import *
    for i in izip_longest([1, 2, 3], ['a', 'b']):
        print I
    輸出為:
    (1, 'a')
    (2, 'b')
    (3, None)
複製程式碼

四、組合生成器

1、itertools.product(*iterable[,repeat]) 這個工具就是產生多個列表或者迭代器的n維積。如果沒有特別指定repeat預設為列表和迭代器的數量。

    例:
    import itertools
    a = (1, 2, 3)
    b = ('A', 'B', 'C')
    c = itertools.product(a,b)
    for elem in c:
        print elem
    輸出為:
    (1, 'A')
    (1, 'B')
    (1, 'C')
    (2, 'A')
    (2, 'B')
    (2, 'C')
    (3, 'A')
    (3, 'B')
    (3, 'C')
複製程式碼

2、itertools.permutations(iterable[,r]) 這個函式作用其實就是產生指定數目repeat的元素的所有排列,且順序有關,但是遇到原列表或者迭代器有重複元素的現象的時候,也會對應的產生重複項。這個時候最好用groupby或者其他filter去一下重,如果有需要的話。

    例:
    import itertools
    x = itertools.permutations(range(4), 3)
    print(list(x))
    輸出為:
    [(0, 1, 2), 
    (0, 1, 3), 
    (0, 2, 1), 
    (0, 2, 3), 
    (0, 3, 1), 
    (0, 3, 2), 
    (1, 0, 2), 
    (1, 0, 3), 
    (1, 2, 0), 
    (1, 2, 3), 
    (1, 3, 0), 
    (1, 3, 2), 
    (2, 0, 1), 
    (2, 0, 3), 
    (2, 1, 0), 
    (2, 1, 3), 
    (2, 3, 0), 
    (2, 3, 1), 
    (3, 0, 1),
    (3, 0, 2), 
    (3, 1, 0), 
    (3, 1, 2), 
    (3, 2, 0), 
    (3, 2, 1)
    ]
複製程式碼

3、itertools.combinations(iterable,r) 這個函式用來生成指定數目r的元素不重複的所有組合。注意和permutation的區分,以及這個組合是無序的,只考慮元素本身的unique性。

    例:
    import itertools
    x = itertools.combinations(range(4), 3)
    print(list(x))
    輸出為:
    [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]
複製程式碼

4、itertools.combinations_with_replacement(iterable,r) 這個函式用來生成指定數目r的元素可重複的所有組合。然而這個函式依然要保證元素組合的unique性。

    例:
    import itertools
    x = itertools.combinations_with_replacement('ABC', 2)
    print(list(x))
    輸出為:
    [('A', 'A'), 
    ('A', 'B'), 
    ('A', 'C'), 
    ('B', 'B'), 
    ('B', 'C'), 
    ('C', 'C’)
    ]
複製程式碼

相關文章