篇文章主要介紹了Python itertools模塊詳解,本文基本是基於文檔的翻譯和補充,相當於翻譯了,需要的朋友可以參考下
這貨很強大, 必須掌握
文檔 鏈接 http://docs.python.org/2/library/itertools.html
pymotw 鏈接 http://pymotw.com/2/itertools/
基本是基於文檔的翻譯和補充,相當於翻譯了
itertools用於高效循環的迭代函數集合
組成
總體,整體了解
無限迭代器
代碼如下:
迭代器 參數 結果 例子
count() start, [step] start, start+step, start+2*step, ... count(10) --> 10 11 12 13 14 ...
cycle() p p0, p1, ... plast, p0, p1, ... cycle('ABCD') --> A B C D A B C D ...
repeat() elem [,n] elem, elem, elem, ... endlessly or up to n times repeat(10, 3) --> 10 10 10
處理輸入序列迭代器
代碼如下:
迭代器 參數 結果 例子
chain() p, q, ... p0, p1, ... plast, q0, q1, ... chain('ABC', 'DEF') --> A B C D E F
compress() data, selectors (d[0] if s[0]), (d[1] if s[1]), ... compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
dropwhile() pred, seq seq[n], seq[n+1], starting when pred fails dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
groupby() iterable[, keyfunc] sub-iterators grouped by value of keyfunc(v)
ifilter() pred, seq elements of seq where pred(elem) is True ifilter(lambda x: x%2, range(10)) --> 1 3 5 7 9
ifilterfalse() pred, seq elements of seq where pred(elem) is False ifilterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8
islice() seq, [start,] stop [, step] elements from seq[start:stop:step] islice('ABCDEFG', 2, None) --> C D E F G
imap() func, p, q, ... func(p0, q0), func(p1, q1), ... imap(pow, (2,3,10), (5,2,3)) --> 32 9 1000
starmap() func, seq func(*seq[0]), func(*seq[1]), ... starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000
tee() it, n it1, it2 , ... itn splits one iterator into n
takewhile() pred, seq seq[0], seq[1], until pred fails takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
izip() p, q, ... (p[0], q[0]), (p[1], q[1]), ... izip('ABCD', 'xy') --> Ax By
izip_longest() p, q, ... (p[0], q[0]), (p[1], q[1]), ... izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
組合生成器
代碼如下:
迭代器 參數 結果
product() p, q, ... [repeat=1] cartesian product, equivalent to a nested for-loop
permutations() p[, r] r-length tuples, all possible orderings, no repeated elements
combinations() p, r r-length tuples, in sorted order, no repeated elements
combinations_with_replacement() p, r r-length tuples, in sorted order, with repeated elements
product('ABCD', repeat=2) AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
permutations('ABCD', 2) AB AC AD BA BC BD CA CB CD DA DB DC
combinations('ABCD', 2) AB AC AD BC BD CD
combinations_with_replacement('ABCD', 2) AA AB AC AD BB BC BD CC CD DD
第一部分
itertools.count(start=0, step=1)
創建一個迭代器,生成從n開始的連續整數,如果忽略n,則從0開始計算(注意:此迭代器不支持長整數)
如果超出了sys.maxint,計數器將溢出並繼續從-sys.maxint-1開始計算。
定義
代碼如下:
def count(start=0, step=1):
# count(10) --> 10 11 12 13 14 ...
# count(2.5, 0.5) -> 2.5 3.0 3.5 ...
n = start
while True:
yield n
n += step
等同於(start + step * i for i in count())
使用
代碼如下:
from itertools import *
for i in izip(count(1), ['a', 'b', 'c']):
print i
(1, 'a')
(2, 'b')
(3, 'c')
itertools.repeat(object[, times])
創建一個迭代器,重復生成object,times(如果已提供)指定重復計數,如果未提供times,將無止盡返回該對象。
定義
代碼如下:
def repeat(object, times=None):
# repeat(10, 3) --> 10 10 10
if times is None:
while True:
yield object
else:
for i in xrange(times):
yield object
使用
代碼如下:
from itertools import *
for i in repeat('over-and-over', 5):
print i
over-and-over
over-and-over
over-and-over
over-and-over
over-and-over
第二部分
itertools.chain(*iterables)
將多個迭代器作為參數, 但只返回單個迭代器, 它產生所有參數迭代器的內容, 就好像他們是來自於一個單一的序列.
代碼如下:
def chain(*iterables):
# chain('ABC', 'DEF') --> A B C D E F
for it in iterables:
for element in it:
yield element
使用
代碼如下:
from itertools import *
for i in chain([1, 2, 3], ['a', 'b', 'c']):
print i
1
2
3
a
b
c
from itertools import chain, imap
def flatmap(f, items):
return chain.from_iterable(imap(f, items))
>>> list(flatmap(os.listdir, dirs))
>>> ['settings.py', 'wsgi.py', 'templates', 'app.py',
'templates', 'index.html, 'config.json']
itertools.compress(data, selectors)
提供一個選擇列表,對原始數據進行篩選
代碼如下:
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)
itertools.dropwhile(predicate, iterable)
創建一個迭代器,只要函數predicate(item)為True,就丟棄iterable中的項,如果predicate返回False,就會生成iterable中的項和所有後續項。
即:在條件為false之後的第一次, 返回迭代器中剩下來的項.
代碼如下:
def dropwhile(predicate, iterable):
# dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
iterable = iter(iterable)
for x in iterable:
if not predicate(x):
yield x
break
for x in iterable:
yield x
使用
代碼如下:
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
itertools.groupby(iterable[, key])
返回一個產生按照key進行分組後的值集合的迭代器.
如果iterable在多次連續迭代中生成了同一項,則會定義一個組,如果將此函數應用一個分類列表,那麼分組將定義該列表中的所有唯一項,key(如果已提供)是一個函數,應用於每一項,如果此函數存在返回值,該值將用於後續項而不是該項本身進行比較,此函數返回的迭代器生成元素(key, group),其中key是分組的鍵值,group是迭代器,生成組成該組的所有項。
即:按照keyfunc函數對序列每個元素執行後的結果分組(每個分組是一個迭代器), 返回這些分組的迭代器
等價於
代碼如下:
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 groupby
qs = [{'date' : 1},{'date' : 2}]
[(name, list(group)) for name, group in itertools.groupby(qs, lambda p:p['date'])]
Out[77]: [(1, [{'date': 1}]), (2, [{'date': 2}])]
>>> 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']
另一個例子
代碼如下:
from itertools import *
from operator import itemgetter
d = dict(a=1, b=2, c=1, d=2, e=1, f=2, g=3)
di = sorted(d.iteritems(), key=itemgetter(1))
for k, g in groupby(di, key=itemgetter(1)):
print k, map(itemgetter(0), g)
1 ['a', 'c', 'e']
2 ['b', 'd', 'f']
3 ['g']
itertools.ifilter(predicate, iterable)
返回的是迭代器類似於針對列表的內置函數 filter() , 它只包括當測試函數返回true時的項. 它不同於 dropwhile()
創建一個迭代器,僅生成iterable中predicate(item)為True的項,如果predicate為None,將返回iterable中所有計算為True的項
對函數func執行返回真的元素的迭代器
代碼如下:
def ifilter(predicate, iterable):
# ifilter(lambda x: x%2, range(10)) --> 1 3 5 7 9
if predicate is None:
predicate = bool
for x in iterable:
if predicate(x):
yield x
使用
代碼如下:
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
itertools.ifilterfalse(predicate, iterable)
和ifilter(函數相反 , 返回一個包含那些測試函數返回false的項的迭代器)
創建一個迭代器,僅生成iterable中predicate(item)為False的項,如果predicate為None,則返回iterable中所有計算為False的項 對函數func執行返回假的元素的迭代器
代碼如下:
def ifilterfalse(predicate, iterable):
# ifilterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8
if predicate is None:
predicate = bool
for x in iterable:
if not predicate(x):
yield x
使用
復制代碼 代碼如下:
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
itertools.islice(iterable, stop)
itertools.islice(iterable, start, stop[, step])
返回的迭代器是返回了輸入迭代器根據索引來選取的項
創建一個迭代器,生成項的方式類似於切片返回值: iterable[start : stop : step],將跳過前start個項,迭代在stop所指定的位置停止,step指定用於跳過項的步幅。 與切片不同,負值不會用於任何start,stop和step, 如果省略了start,迭代將從0開始,如果省略了step,步幅將采用1.
返回序列seq的從start開始到stop結束的步長為step的元素的迭代器
代碼如下:
def islice(iterable, *args):
# islice('ABCDEFG', 2) --> A B
# islice('ABCDEFG', 2, 4) --> C D
# islice('ABCDEFG', 2, None) --> C D E F G
# islice('ABCDEFG', 0, None, 2) --> A C E G
s = slice(*args)
it = iter(xrange(s.start or 0, s.stop or sys.maxint, s.step or 1))
nexti = next(it)
for i, element in enumerate(iterable):
if i == nexti:
yield element
nexti = next(it)
使用
代碼如下:
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
itertools.imap(function, *iterables)
創建一個迭代器,生成項function(i1, i2, ..., iN),其中i1,i2...iN分別來自迭代器iter1,iter2 ... iterN,如果function為None,則返回(i1, i2, ..., iN)形式的元組,只要提供的一個迭代器不再生成值,迭代就會停止。
即:返回一個迭代器, 它是調用了一個其值在輸入迭代器上的函數, 返回結果. 它類似於內置函數 map() , 只是前者在任意輸入迭代器結束後就停止(而不是插入None值來補全所有的輸入).
返回序列每個元素被func執行後返回值的序列的迭代器
代碼如下:
def imap(function, *iterables):
# imap(pow, (2,3,10), (5,2,3)) --> 32 9 1000
iterables = map(iter, iterables)
while True:
args = [next(it) for it in iterables]
if function is None:
yield tuple(args)
else:
yield function(*args)
使用
代碼如下:
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
itertools.starmap(function, iterable)
創建一個迭代器,生成值func(*item),其中item來自iterable,只有當iterable生成的項適用於這種調用函數的方式時,此函數才有效。
對序列seq的每個元素作為func的參數列表執行, 返回執行結果的迭代器
代碼如下:
def starmap(function, iterable):
# starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000
for args in iterable:
yield function(*args)
使用
代碼如下:
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
itertools.tee(iterable[, n=2])
返回一些基於單個原始輸入的獨立迭代器(默認為2). 它和Unix上的tee工具有點語義相似, 也就是說它們都重復讀取輸入設備中的值並將值寫入到一個命名文件和標准輸出中
從iterable創建n個獨立的迭代器,創建的迭代器以n元組的形式返回,n的默認值為2,此函數適用於任何可迭代的對象,但是,為了克隆原始迭代器,生成的項會被緩存,並在所有新創建的迭代器中使用,一定要注意,不要在調用tee()之後使用原始迭代器iterable,否則緩存機制可能無法正確工作。
把一個迭代器分為n個迭代器, 返回一個元組.默認是兩個
代碼如下:
def tee(iterable, n=2):
it = iter(iterable)
deques = [collections.deque() for i in range(n)]
def gen(mydeque):
while True:
if not mydeque: # when the local deque is empty
newval = next(it) # fetch a new value and
for d in deques: # load it to all the deques
d.append(newval)
yield mydeque.popleft()
return tuple(gen(d) for d in deques)
使用
代碼如下:
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
itertools.takewhile(predicate, iterable)
和dropwhile相反
創建一個迭代器,生成iterable中predicate(item)為True的項,只要predicate計算為False,迭代就會立即停止。
即:從序列的頭開始, 直到執行函數func失敗.
代碼如下:
def takewhile(predicate, iterable):
# takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
for x in iterable:
if predicate(x):
yield x
else:
break
使用
代碼如下:
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
itertools.izip(*iterables)
返回一個合並了多個迭代器為一個元組的迭代器. 它類似於內置函數zip(), 只是它返回的是一個迭代器而不是一個列表
創建一個迭代器,生成元組(i1, i2, ... iN),其中i1,i2 ... iN 分別來自迭代器iter1,iter2 ... iterN,只要提供的某個迭代器不再生成值,迭代就會停止,此函數生成的值與內置的zip()函數相同。
代碼如下:
izip(iter1, iter2, ... iterN):
返回:(it1[0],it2 [0], it3[0], ..), (it1[1], it2[1], it3[1], ..)...
def izip(*iterables):
# izip('ABCD', 'xy') --> Ax By
iterators = map(iter, iterables)
while iterators:
yield tuple(map(next, iterators))
使用
代碼如下:
from itertools import *
for i in izip([1, 2, 3], ['a', 'b', 'c']):
print i
(1, 'a')
(2, 'b')
(3, 'c')
itertools.izip_longest(*iterables[, fillvalue])
與izip()相同,但是迭代過程會持續到所有輸入迭代變量iter1,iter2等都耗盡為止,如果沒有使用fillvalue關鍵字參數指定不同的值,則使用None來填充已經使用的迭代變量的值。
代碼如下:
class ZipExhausted(Exception):
pass
def izip_longest(*args, **kwds):
# izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
fillvalue = kwds.get('fillvalue')
counter = [len(args) - 1]
def sentinel():
if not counter[0]:
raise ZipExhausted
counter[0] -= 1
yield fillvalue
fillers = repeat(fillvalue)
iterators = [chain(it, sentinel(), fillers) for it in args]
try:
while iterators:
yield tuple(map(next, iterators))
except ZipExhausted:
pass
第三部分
itertools.product(*iterables[, repeat])
笛卡爾積
創建一個迭代器,生成表示item1,item2等中的項目的笛卡爾積的元組,repeat是一個關鍵字參數,指定重復生成序列的次數。
代碼如下:
def product(*args, **kwds):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = map(tuple, args) * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
例子
代碼如下:
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')
itertools.permutations(iterable[, r])
排列
創建一個迭代器,返回iterable中所有長度為r的項目序列,如果省略了r,那麼序列的長度與iterable中的項目數量相同: 返回p中任意取r個元素做排列的元組的迭代器
代碼如下:
def permutations(iterable, r=None):
# permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
# permutations(range(3)) --> 012 021 102 120 201 210
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
if r > n:
return
indices = range(n)
cycles = range(n, n-r, -1)
yield tuple(pool[i] for i in indices[:r])
while n:
for i in reversed(range(r)):
cycles[i] -= 1
if cycles[i] == 0:
indices[i:] = indices[i+1:] + indices[i:i+1]
cycles[i] = n - i
else:
j = cycles[i]
indices[i], indices[-j] = indices[-j], indices[i]
yield tuple(pool[i] for i in indices[:r])
break
else:
return
也可以用product實現
def permutations(iterable, r=None):
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
for indices in product(range(n), repeat=r):
if len(set(indices)) == r:
yield tuple(pool[i] for i in indices)
itertools.combinations(iterable, r)
創建一個迭代器,返回iterable中所有長度為r的子序列,返回的子序列中的項按輸入iterable中的順序排序 (不帶重復)
代碼如下:
def combinations(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
return
indices = range(r)
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
yield tuple(pool[i] for i in indices)
#或者
def combinations(iterable, r):
pool = tuple(iterable)
n = len(pool)
for indices in permutations(range(n), r):
if sorted(indices) == list(indices):
yield tuple(pool[i] for i in indices)
itertools.combinations_with_replacement(iterable, r)
創建一個迭代器,返回iterable中所有長度為r的子序列,返回的子序列中的項按輸入iterable中的順序排序 (帶重復)
代碼如下:
def combinations_with_replacement(iterable, r):
# combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC
pool = tuple(iterable)
n = len(pool)
if not n and r:
return
indices = [0] * r
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != n - 1:
break
else:
return
indices[i:] = [indices[i] + 1] * (r - i)
yield tuple(pool[i] for i in indices)
或者
def combinations_with_replacement(iterable, r):
pool = tuple(iterable)
n = len(pool)
for indices in product(range(n), repeat=r):
if sorted(indices) == list(indices):
yield tuple(pool[i] for i in indices)
第四部分
擴展
使用現有擴展功能
代碼如下:
def take(n, iterable):
"Return first n items of the iterable as a list"
return list(islice(iterable, n))
def tabulate(function, start=0):
"Return function(0), function(1), ..."
return imap(function, count(start))
def consume(iterator, n):
"Advance the iterator n-steps ahead. If n is none, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
def nth(iterable, n, default=None):
"Returns the nth item or a default value"
return next(islice(iterable, n, None), default)
def quantify(iterable, pred=bool):
"Count how many times the predicate is true"
return sum(imap(pred, iterable))
def padnone(iterable):
"""Returns the sequence elements and then returns None indefinitely.
Useful for emulating the behavior of the built-in map() function.
"""
return chain(iterable, repeat(None))
def ncycles(iterable, n):
"Returns the sequence elements n times"
return chain.from_iterable(repeat(tuple(iterable), n))
def dotproduct(vec1, vec2):
return sum(imap(operator.mul, vec1, vec2))
def flatten(listOfLists):
"Flatten one level of nesting"
return chain.from_iterable(listOfLists)
def repeatfunc(func, times=None, *args):
"""Repeat calls to func with specified arguments.
Example: repeatfunc(random.random)
"""
if times is None:
return starmap(func, repeat(args))
return starmap(func, repeat(args, times))
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
pending = len(iterables)
nexts = cycle(iter(it).next for it in iterables)
while pending:
try:
for next in nexts:
yield next()
except StopIteration:
pending -= 1
nexts = cycle(islice(nexts, pending))
def powerset(iterable):
"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):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(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):
"List unique elements, preserving order. Remember only the element just seen."
# unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
# unique_justseen('ABBCcAD', str.lower) --> A B C A D
return imap(next, imap(itemgetter(1), groupby(iterable, key)))
def iter_except(func, exception, first=None):
""" Call a function repeatedly until an exception is raised.
Converts a call-until-exception interface to an iterator interface.
Like __builtin__.iter(func, sentinel) but uses an exception instead
of a sentinel to end the loop.
Examples:
bsddbiter = iter_except(db.next, bsddb.error, db.first)
heapiter = iter_except(functools.partial(heappop, h), IndexError)
dictiter = iter_except(d.popitem, KeyError)
dequeiter = iter_except(d.popleft, IndexError)
queueiter = iter_except(q.get_nowait, Queue.Empty)
setiter = iter_except(s.pop, KeyError)
"""
try:
if first is not None:
yield first()
while 1:
yield func()
except exception:
pass
def random_product(*args, **kwds):
"Random selection from itertools.product(*args, **kwds)"
pools = map(tuple, args) * kwds.get('repeat', 1)
return tuple(random.choice(pool) for pool in pools)
def random_permutation(iterable, r=None):
"Random selection from itertools.permutations(iterable, r)"
pool = tuple(iterable)
r = len(pool) if r is None else r
return tuple(random.sample(pool, r))
def random_combination(iterable, r):
"Random selection from itertools.combinations(iterable, r)"
pool = tuple(iterable)
n = len(pool)
indices = sorted(random.sample(xrange(n), r))
return tuple(pool[i] for i in indices)
def random_combination_with_replacement(iterable, r):
"Random selection from itertools.combinations_with_replacement(iterable, r)"
pool = tuple(iterable)
n = len(pool)
indices = sorted(random.randrange(n) for i in xrange(r))
return tuple(pool[i] for i in indices)
def tee_lookahead(t, i):
"""Inspect the i-th upcomping value from a tee object
while leaving the tee object at its current position.
Raise an IndexError if the underlying iterator doesn't
have enough values.
"""
for value in islice(t.__copy__(), i, None):
return value
raise IndexError(i)
自定義擴展
將序列按大小切分,更好的性能
代碼如下:
from itertools import chain, islice
def chunks(iterable, size, format=iter):
it = iter(iterable)
while True:
yield format(chain((it.next(),), islice(it, size - 1)))
>>> l = ["a", "b", "c", "d", "e", "f", "g"]
>>> for chunk in chunks(l, 3, tuple):...
print chunk...
("a", "b", "c")
("d", "e", "f")
("g",)
補充
迭代工具,你最好的朋友
迭代工具模塊包含了操做指定的函數用於操作迭代器。想復制一個迭代器出來?鏈接兩個迭代器?以one liner(這裡的one-liner只需一行代碼能搞定的任務)用內嵌的列表組合一組值?不使用list創建Map/Zip?···,你要做的就是 import itertools,舉個例子吧:
四匹馬賽跑到達終點排名的所有可能性:
代碼如下:
>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]
理解迭代的內部機制: 迭代(iteration)就是對可迭代對象(iterables,實現了__iter__()方法)和迭代器(iterators,實現了__next__()方法)的一個操作過程。可迭代對象是任何可返回一個迭代器的對象,迭代器是應用在迭代對象中迭代的對象,換一種方式說的話就是:iterable對象的__iter__()方法可以返回iterator對象,iterator通過調用next()方法獲取其中的每一個值(譯者注),讀者可以結合Java API中的 Iterable接口和Iterator接口進行類比。