一、多个序列迭代
有时候我们希望能够同时遍历多个序列,比如有序列a = [1, 2, 3, 4, 5], b = ['a', 'b', 'c', 'd', 'e'],我们如果要同时遍历的话,可以采用如下的方式:
- >>> xpts = [1, 5, 4, 2, 10, 7]
- >>> ypts = [101, 78, 37, 15, 62, 99]
- >>> for x, y in zip(xpts, ypts):
- ... print(x, y)
- ...
- 1 101
- 5 78
- 4 37
- 2 15
- 10 62
- 7 99
因为使用了zip()方法,我们将两个集合里的内容都同时取出来,按照tuple的方式一个个的组织起来。所以我们访问的时候也是通过一个个tuple的方式来读取。这里我们提供的两个list是长度一致的,如果不一致会怎么样呢?我们再来试试另外两个序列:- >>> a = [1, 2, 3, 4]
- >>> b = ['a', 'b', 'c']
- >>> for x, y in zip(a, b):
- ... print(x, y)
- ...
- 1 a
- 2 b
- 3 c
从代码运行的结果来看,默认是遍历到短的那个序列结束。如果我们需要到那个长的序列结束呢?这里有另外一种办法:
- >>> from itertools import zip_longest
- >>> for i in zip_longest(a, b):
- ... print(i)
- ...
- (1, 'a')
- (2, 'b')
- (3, 'c')
- (4, None)
这里引用了zip_longest方法,它可以将两个序列组合起来,不过对于短的那个序列,用None来补齐。将几个序列串在一起
我们可以直接看如下的代码:
- >>> from itertools import chain
- >>> a = [1, 2, 3, 4]
- >>> b = ['a', 'b', 'c']
- >>> for x in chain(a, b):
- ... print(x)
- ...
- 1
- 2
- 3
- 4
- a
- b
- c
一个chain方法就解决了大部分问题了。和我们默认想到的方法比起来,chain方法效率更加高。因为我们最开始会考虑将两个或者多个序列连在一起,比如a + b,这样会创造一个新的序列出来,这样带来的成本开销明显偏大了。
将嵌套的序列变平
这是一个有意思的问题,因为一般来说当我们需要访问一个数组的时候,比如说a = [1, 2, [3, 4, [5, 6], 7, 8], 9, 10],我们希望能够将他们所有的元素都输出,并使得他们看起来像就是一个一维数组那样,如a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]。我们默认的思路该怎么办呢?只怕一开始就是碰到一个元素的时候会判断它是否为数组,如果是的则递归的去输出它的元素。
Python里面有一个很强大的特性可以很好的实现这个方法:
- from collections import Iterable
-
- def flatten(items, ignore_types=(str, bytes)):
- for x in items:
- if isinstance(x, Iterable) and not isinstance(x, ignore_types):
- yield from flatten(x)
- else:
- yield x
这种实现里面有一个额外的ignore_types,里面列举了一些类型我们可以不需要进一步的去遍历。比如说str,我们一般碰到一个字符串可以直接将他们作为一个整的对象输出而不是再对它们进一步拆分的遍历。最有意思的地方在yield from这个部分。yield from这个部分的意思是将后续的值作为它本身的一个subroutine。所以它们就会被当作一个拉平的数组。关于yield from这部分我们在后面的文章中会专门讲述。
按照这个方式,我们使用它们的代码如下:
- >>> from nested import flatten
- >>> items = [1, 2, [3, 4, [5, 6], 7], 8]
- >>> for x in flatten(items):
- ... print(x)
- ...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
迭代多个有序排列数组
这个问题不太好用一句话描述,就是说假定我们有若干个已经排序的数组了。当我们希望能够去遍历这所有的序列,但是保证我们每次都取出他们中间最小的元素,保证所有输出还是一个严格排序的结果,我们该怎么办呢?实际上,这是一个多路归并排序的问题。在前面的一些文章里有过讨论,不过要做一个好的java实现我们可是费了一番功夫。这里有什么好的招呢?
- >>> import heapq
- >>> a = [1, 4, 7, 10]
- >>> b = [2, 5, 6, 11]
- >>> for c in heapq.merge(a, b):
- ... print(c)
- ...
- 1
- 2
- 4
- 5
- 6
- 7
- 10
- 11
这里是归并两路的数据结果。在一些我们如果要归并多个文件的情况下,也可以这样来做。因为这里heapq.merge不是一次将所有的数据都装载到内存里,它只是每次取很小的一部分,像generator一样。所以对于大文件的合并用这种方式来做。呵呵,寥寥几行代码就解决了问题,不能不说,很好很强大啊。
总结
Iterator的定义方法虽然看起来很简单,但是它的使用也可以非常的复杂和灵活。通过结合一些库的支持,我们可以实现非常强大的计算效果。当然,前提是我们需要知道去哪里找到这些库和知道这些用法。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。