文章来自《Python cookbook》.

翻译仅仅是为了个人学习,其它商业版权纠纷与此无关!

-- Zoom.Quiet [2004-08-11 01:21:53]

1. 在索引和序列元素上并行循环

1.14 Looping in Parallel over Index and Sequence Items

Credit: Alex Martelli

1.1. 问题 Problem

You need to loop on a sequence, but at each step you also need to know what index into the sequence you have reached.

你需要在一个序列上循环,但是在每一步,你也需要知道什么索引进入到你已经到达的序列中。

1.2. 解决 Solution

Together, the built-in functions xrange and zip make this easy. You need only this one instance of xrange, as it is fully reusable:

把内建函数xrange和zip放在一起将使它很容易。你只需要xrange的一个实例,好像它完全可重用。

   1 indices = xrange(sys.maxint)

Here's how you use the indices instance:

这儿是你怎么样使用index的实例

   1 for item, index in zip(sequence, indices):
   2     something(item, index)

This gives the same semantics as:

给出相同的语义:

   1 for index in range(len(sequence)):
   2     something(sequence[index], index)

but the change of emphasis allows greater clarity in many usage contexts.

但是改变的重点允许在更多使用环境中更加清楚。

Another alternative is to use class wrappers:

另一个可选择的是使用一个包装类:

   1 class Indexed:
   2     def _ _init_ _(self, seq):
   3         self.seq = seq
   4     def _ _getitem_ _(self, i):
   5         return self.seq[i], i

For example:

例如

   1 for item, index in Indexed(sequence):
   2     something(item, index)

In Python 2.2, with from _ _future_ _ import generators, you can also use:

在python2.2, 从_ _future_ _导入一个产生器, 你也可以使用:

   1 def Indexed(sequence):
   2     iterator = iter(sequence)
   3     for index in indices:
   4         yield iterator.next(  ), index
   5     # Note that we exit by propagating StopIteration when .next raises it!

However, the simplest roughly equivalent way remains the good old:

然而,最简单粗糙的等价方法仍然是老的:

   1 def Indexed(sequence):
   2     return zip(sequence, indices)

1.3. 讨论 Discussion

We often want to loop on a sequence but also need the current index in the loop body. The canonical Pydiom for this is:

我们经常想在一个序列上循环但是也需要在循环体上的当前索引。为了这个目的,规范的python化的是:

for i in range(len(sequence)):

using sequence[i] as the item reference in the loop's body. However, in many contexts, it is clearer to emphasize the loop on the sequence items rather than on the indexes. zip provides an easy alternative, looping on indexes and items in parallel, since it truncates at the shortest of its arguments. Thus, it's okay for some arguments to be unbounded sequences, as long as not all the arguments are unbounded. An unbounded sequence of indexes is trivial to write (xrange is handy for this), and a reusable instance of that sequence can be passed to zip, in parallel to the sequence being indexed.

使用sequence[i]作为元素在循环体上的引用。然而,在许多环境中,在序列元素上强调循环而不是在索引上更清楚。Zip提供一个简单的选择,在索引和元素上并行循环。因为它把它的参数截断到最短。这样,对于一些没有被绑定序列的参数是可行的。只要不是所有的参数都是未绑定的。写一个未绑定的索引的序列是没有价值的(对这个xrange是方便的)。 并且那个序列的一个可重用的是列能够被传递到zip, 并行的这个序列被索引。

The same zip usage also affords a client code-transparent alternative to the use of a wrapper class Indexed, as demonstrated by the Indexed class, generator, and function shown in the solution. Of these, when applicable, zip is simplest.

相同的zip使用也提供一个客户的代码透明的索引一个包装类的使用的选择。象通过索引一个类示范的那样,产生器,和函数显示在解决方案里。当这些可适用的时候,zip是最简单的。

The performance of each of these solutions is roughly equivalent. They're all O(N) (i.e., they execute in time proportional to the number of elements in the sequence), they all take O(1) extra memory, and none is anything close to twice as fast or as slow as another.

这些解决方案中的每一个都几乎等价。他们都是O(N)(他们执行的时间和序列里的元素个数成正比)。他们都使用O(1)的而外内存。并且没有一个是比其他快两倍或慢两倍。

Note that zip is not lazy (i.e., it cannot accept all argument sequences being unbounded). Therefore, in certain cases in which zip cannot be used (albeit not the typical one in which range(len(sequence)) is the alternative), other kinds of loop might be usable. See Recipe 17.13 for lazy, iterator-based alternatives, including an xzip function (Python 2.2 only).

注意,zip不是延迟的(它不能接受所有未被绑定的序列参数)。所以,在一些情况下,zip不能被使用(虽然range(len(sequence))是可选择的并不典型)。但是其他种类的循环或许可以被使用。看Recipe 17.13为了延迟,基于迭代的一个选择,包括一个xzip函数(仅仅在python2.2)

1.4. 参考 See Also

Recipe 17.13; the Library Reference section on sequence types.