ホームページ  >  記事  >  バックエンド開発  >  Python 迭代器工具包【推荐】

Python 迭代器工具包【推荐】

不言
不言オリジナル
2018-05-26 14:50:231635ブラウズ

      0x01 介绍了迭代器的概念,即定义了 __iter__() __next__() 方法的对象,或者通过 yield 简化定义的“可迭代对象”,而在一些函数式编程语言(见 0x02 Python 中的函数式编程)中,类似的迭代器常被用于产生特定格式的列表(或序列),这时的迭代器更像是一种数据结构而非函数(当然在一些函数式编程语言中,这两者并无本质差异)。Python 借鉴了 APL, Haskell, and SML 中的某些迭代器的构造方法,并在 itertools 中实现(该模块是通过 C 实现,源代码:/Modules/itertoolsmodule.c)。

  itertools 模块提供了如下三类迭代器构建工具:

  无限迭代

  整合两序列迭代

  组合生成器

  1. 无限迭代

  所谓无限(infinite)是指如果你通过 for...in... 的语法对其进行迭代,将陷入无限循环,包括:  

count(start, [step])

  cycle(p)

  repeat(elem [,n])

  从名字大概可以猜出它们的用法,既然说是无限迭代,我们自然不会想要将其所有元素依次迭代取出,而通常是结合 map/zip 等方法,将其作为一个取之不尽的数据仓库,与有限长度的可迭代对象进行组合操作:  

from itertools import cycle, count, repeat
print(count.__doc__)
  count(start=0, step=1) --> count object
  Return a count object whose .__next__() method returns consecutive values.
  Equivalent to:
  def count(firstval=0, step=1):
  x = firstval
  while 1:
  yield x
  x += step
  counter = count()
  print(next(counter))
  print(next(counter))
  print(list(map(lambda x, y: x+y, range(10), counter)))
  odd_counter = map(lambda x: 'Odd#{}'.format(x), count(1, 2))
  print(next(odd_counter))
  print(next(odd_counter))

  0

  1

  [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

  Odd#1

  Odd#3

  print(cycle.__doc__)

  cycle(iterable) --> cycle object

  Return elements from the iterable until it is exhausted.

  Then repeat the sequence indefinitely.

  cyc = cycle(range(5))

  print(list(zip(range(6), cyc)))

  print(next(cyc))

  print(next(cyc))

  [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 0)]

  1

  2

  print(repeat.__doc__)

  repeat(object [,times]) -> create an iterator which returns the object

  for the specified number of times. If not specified, returns the object

  endlessly.

  print(list(repeat('Py', 3)))

  rep = repeat('p')

  print(list(zip(rep, 'y'*3)))

  ['Py', 'Py', 'Py']

  [('p', 'y'), ('p', 'y'), ('p', 'y')]

  2. 整合两序列迭代

  所谓整合两序列,是指以两个有限序列为输入,将其整合操作之后返回为一个迭代器,最为常见的 zip 函数就属于这一类别,只不过 zip 是内置函数。这一类别完整的方法包括: 

 accumulate()

  chain()/chain.from_iterable()

  compress()

  dropwhile()/filterfalse()/takewhile()

  groupby()

  islice()

  starmap()

  tee()

  zip_longest()

  这里就不对所有的方法一一举例说明了,如果想要知道某个方法的用法,基本通过 print(method.__doc__) 就可以了解,毕竟 itertools 模块只是提供了一种快捷方式,并没有隐含什么深奥的算法。这里只对下面几个我觉得比较有趣的方法进行举例说明。  

from itertools import cycle, compress, islice, takewhile, count

  # 这三个方法(如果使用恰当)可以限定无限迭代

  # print(compress.__doc__)

  print(list(compress(cycle('PY'), [1, 0, 1, 0])))

  # 像操作列表 l[start:stop:step] 一样操作其它序列

  # print(islice.__doc__)

  print(list(islice(cycle('PY'), 0, 2)))

  # 限制版的 filter

  # print(takewhile.__doc__)

  print(list(takewhile(lambda x: x < 5, count())))

  [&#39;P&#39;, &#39;P&#39;]

  [&#39;P&#39;, &#39;Y&#39;]

  [0, 1, 2, 3, 4]

  from itertools import groupby

  from operator import itemgetter

  print(groupby.__doc__)

  for k, g in groupby(&#39;AABBC&#39;):

  print(k, list(g))

  db = [dict(name=&#39;python&#39;, script=True),

  dict(name=&#39;c&#39;, script=False),

  dict(name=&#39;c++&#39;, script=False),

  dict(name=&#39;ruby&#39;, script=True)]

  keyfunc = itemgetter(&#39;script&#39;)

  db2 = sorted(db, key=keyfunc) # sorted by `script&#39;

  for isScript, langs in groupby(db2, keyfunc):

  print(&#39;, &#39;.join(map(itemgetter(&#39;name&#39;), langs)))

  groupby(iterable[, keyfunc]) -> create an iterator which returns

  (key, sub-iterator) grouped by each value of key(value).

  A [&#39;A&#39;, &#39;A&#39;]

  B [&#39;B&#39;, &#39;B&#39;]

  C [&#39;C&#39;]

  c, c++

  python, ruby

  from itertools import zip_longest

  # 内置函数 zip 以较短序列为基准进行合并,

  # zip_longest 则以最长序列为基准,并提供补足参数 fillvalue

  # Python 2.7 中名为 izip_longest

  print(list(zip_longest(&#39;ABCD&#39;, &#39;123&#39;, fillvalue=0)))

  [(&#39;A&#39;, &#39;1&#39;), (&#39;B&#39;, &#39;2&#39;), (&#39;C&#39;, &#39;3&#39;), (&#39;D&#39;, 0)]

  3. 组合生成器

  关于生成器的排列组合: 

product(*iterables, repeat=1):两输入序列的笛卡尔乘积

  permutations(iterable, r=None):对输入序列的完全排列组合

  combinations(iterable, r):有序版的排列组合

  combinations_with_replacement(iterable, r):有序版的笛卡尔乘积

  from itertools import product, permutations, combinations, combinations_with_replacement

  print(list(product(range(2), range(2))))

  print(list(product(&#39;AB&#39;, repeat=2)))

  [(0, 0), (0, 1), (1, 0), (1, 1)]

  [(&#39;A&#39;, &#39;A&#39;), (&#39;A&#39;, &#39;B&#39;), (&#39;B&#39;, &#39;A&#39;), (&#39;B&#39;, &#39;B&#39;)]

  print(list(combinations_with_replacement(&#39;AB&#39;, 2)))

  [(&#39;A&#39;, &#39;A&#39;), (&#39;A&#39;, &#39;B&#39;), (&#39;B&#39;, &#39;B&#39;)]

  # 赛马问题:4匹马前2名的排列组合(A^4_2)

  print(list(permutations(&#39;ABCDE&#39;, 2)))

  [(&#39;A&#39;, &#39;B&#39;), (&#39;A&#39;, &#39;C&#39;), (&#39;A&#39;, &#39;D&#39;), 
 (&#39;A&#39;, &#39;E&#39;), (&#39;B&#39;, &#39;A&#39;), (&#39;B&#39;, &#39;C&#39;), 
 (&#39;B&#39;, &#39;D&#39;), (&#39;B&#39;, &#39;E&#39;), (&#39;C&#39;, &#39;A&#39;), 
 (&#39;C&#39;, &#39;B&#39;), (&#39;C&#39;, &#39;D&#39;), (&#39;C&#39;, &#39;E&#39;), 
 (&#39;D&#39;, &#39;A&#39;), (&#39;D&#39;, &#39;B&#39;), (&#39;D&#39;, &#39;C&#39;), 
 (&#39;D&#39;, &#39;E&#39;), (&#39;E&#39;, &#39;A&#39;), (&#39;E&#39;, &#39;B&#39;), (&#39;E&#39;, &#39;C&#39;), (&#39;E&#39;, &#39;D&#39;)]

  # 彩球问题:4种颜色的球任意抽出2个的颜色组合(C^4_2)

  print(list(combinations(&#39;ABCD&#39;, 2)))

  [(&#39;A&#39;, &#39;B&#39;), (&#39;A&#39;, &#39;C&#39;), (&#39;A&#39;, &#39;D&#39;), (&#39;B&#39;, &#39;C&#39;), (&#39;B&#39;, &#39;D&#39;), (&#39;C&#39;, &#39;D&#39;)]
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。