python的itertools库受到了来自APL, Haskell和SML的灵感,并且用最适合python语言特性的形式重构。它差不多可以说是定义了一套高效、节省内存的方法使用纯python来构建开发者所需要的各种不同迭代器。

概览

根据itertools中方法的返回类型不同,可以将这些方法分为三类: 无穷迭代∞

迭代器 参数 返回值 示例
count() start,[step] start,start+step,start+2*step,… count(10) –> 10,11,12,13,14,…
cycle() p p0,p1,p2,…,plast,p0,p1,p2…. cycle([1,2,3,4]) –> 1,2,3,4,1,2,3,4,…
repeat() p,[n] p,p,p,…,p 或者重复n次p repeat(10,2) –> 10,10

处理输入迭代器⌨️

迭代器 参数 返回值 示例
chain() p,q,.. p0,p1,..,plast,q0,q1,…,qlast,…. chain(‘abc’,[1,2,3]) –> a b c 1 2 3
compress() data,selectors (d[0] if s[0]),(d[1] if s[1])… compress(‘abcd’,[0,1,0,0]) –> b
dropwhile() pred,seq seq[n],seq[n+1]… while pred(seq[n-1]) == False dropwhile(lambda x:x<3,[1,2,4,0,1]) –> 4,0,1
groupby() iterable,[keyfunc] 根据keyfunc(iterable item)值返回的迭代器
ifilter() pred,seq 返回seq中pred(seq[n])为真值的一部分元素 ifilter(lambda x:x>3,[1,2,3,4,5,6]) –> 4,5,6
ifilterfalse() pred,seq 返回seq中pred(seq[n])为假的一部分元素 ifilterfalse(lambda x:x>3,[1,2,3,4,5,6]) –> 1,2,3
islice() seq, [start,] stop [, step] 返回seq[start:stop:step]的切片 islice(count(10),1,3) -> 11,12
imap() func, p, q, … func(p0, q0), func(p1, q1), … imap(lambda x,y:x+y,count(0),count(10)) –> 10,11,12,…
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] 返回输入参数的笛卡尔积
permutations() p[, r] 返回由长度为r的p中元素的组合,每个元素不会重复出现 permutations([1,2],2) –> (1, 2), (2, 1)
combinations() p, r 按照p中元素的顺序来进行排列组合,每个元素不会重复出现 combinations([2,1],1) –> (2,), (1,)
combinations_with_replacement() p, r 按照p中元素的顺序来进行排列组合,每个元素可以重复出现 combinations_with_replacement([1,2],2)–> (1, 1), (1, 2), (2, 2)

详解

如下的一些方法都是用来创建或者返回迭代器的,其中一些会返回无限长度的迭代器,如果要将他们用在另外的函数或者循环中的时候需要进行切片操作。

  • itertools.chain(*iterables) 输入参数是一个或者多个迭代器对象,返回的内容是将这些迭代器中的所有元素拼接成为一个大的迭代器,需要注意的是,当作参数输入的若干个迭代器可以是不同的类型(区别于同种类型的序列相加的操作,如两个list相加或者两个string相加). itertools.chain(*iterables)类似于:
1
2
3
4
5
def chain(*iterables):
    # chain('ABC', 'DEF') --> A B C D E F       
    for iterable in iterables:
        for element in iterable:
            yield element
  • classmethod chain.from_iterable(iterable) 将输入参数iterable中的每个可迭代对象中的元素合并成为一个大的迭代器,类似于以下代码:
1
2
3
4
5
def from_iterable(iterable):
    # chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
    for item in iterable:
        for element in item:
            yield element
  • itertools.combinations(iterable, r) 😢 返回一个由r个iterable元素组合而成的迭代器,如果iterable中的元素是经过排序的,那么返回的每个对象也都是经过排序的。iterbale中的每个元素都是按照它在iterable中所在的位置进行处理。itertools.combinations(iterable, r)类似于如下代码过程:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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)

或者

1
2
3
4
5
6
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.compress(data, selectors) 输入参数data和selectors均为迭代器对象,如果selector中某一元素返回真值,则返回对应位置data中的元素。类似于代码:
1
2
3
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.count(start=0, step=1) 用于返回一个数值连续的迭代器,常作为imap()或者izip()的参数。等价于代码:
1
2
3
4
5
6
7
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
  • itertools.cycle(iterable) 逐个返回iterable中的元素,并将每个元素备份,在iterable中元素耗尽的时候,重复的返回iterable对象的备份。等价于:
1
2
3
4
5
6
7
8
def cycle(iterable):
    container = []
    for item in iterable:
        yield item
        container.append(item)
    while container:
        for element in container:
            yield element
  • itertools.dropwhile(predicate, iterable) 如果predicate返回值为True,就将iterable中的元素抛弃,直到predicate返回False,返回iterable中剩下的元素。类似于代码实现:
1
2
3
4
5
6
7
8
def dropwhile(pred,iteration):
    iterable = iter(iteration)
    for x in iterable:
        if not pred(x):
            yield x
            break
    for x in iterable:
        yield x
  • itertools.ifilter(predicate, iterable) 如果iterable中的元素element,在执行predicate(element)返回True,则将这个element返回。如果predicate为None,则返回iterable中的真值。类似于:
1
2
3
4
5
6
def ifilter(pred,iterable):
    if pred is None:
        pred = bool
    for item in iterable:
        if pred(item):
            yield item
  • itertools.ifilterfalse(predicate, iterable)itertools.ifilter相反,类似于代码:
1
2
3
4
5
6
def ifileterfalse(pred,iterable):
    if pred is None:
        pred = bool
    for item in iterable:
        if not pred(item):
            yield item
  • itertools.imap(function, *iterables) 将来自于iterables中多个迭代器中的每次各选取一个元素作为function的参数,返回function执行后的结果.如果function为空,缺省值为tuple。区别于map,imap中的迭代器可以是无穷序列,并且imap中当最短的迭代器中没有元素的时候会结束,而不是使用None来代替。执行代码类似于:
1
2
3
4
5
6
7
def imap(func,*iterables):
    its = map(iter,iterables)
    if func is None:
        func = tuple
    while True:
        args = [next(it) for it in its]
        yield func(*args)
  • itertools.islice(iterable, stop) itertools.islice(iterable, start, stop[, step]) 与普通的slice方法不同,islice的参数start,stop或者step不能为负值,类似于代码:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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)
  • itertools.izip(*iterables) 与zip不同,izip的返回值是一个迭代器而不是list对象。运行代码类似于:
1
2
3
4
def izip(*iterables):
    iters = map(iter,iterables)
    while iters:
        yield tuple(map(next,iters))
  • itertools.repeat(object[, times]) 生成一个重复出现object times次的迭代器,类似代码:
1
2
3
4
5
6
7
def repeat(object,times):
    if times is None:
        while True:
            yield object
    else:
        for x in rang(times):
            yield object
  • itertools.starmap(function, iterable) 实现类似代码:
1
2
3
def starmap(func,iterable):
    for item in iterable:
        yield func(*item)