Loops Python循环:习惯性地比较列表中的连续项

Loops Python循环:习惯性地比较列表中的连续项,loops,iterator,python,Loops,Iterator,Python,我需要在一个对象列表上循环,像这样比较它们:0对1,1对2,2对3,等等(我使用pysvn提取一个差异列表)。我只是在一个索引上循环,但我一直想知道是否有更接近惯用的方法来做。它是Python;我不应该以某种巧妙的方式使用迭代器吗?简单地在索引上循环似乎很清楚,但我想知道是否有一种更具表现力或简洁的方法来实现它 for revindex in xrange(len(dm_revisions) - 1): summary = \ svn.diff_summarize(svn

我需要在一个对象列表上循环,像这样比较它们:0对1,1对2,2对3,等等(我使用pysvn提取一个差异列表)。我只是在一个索引上循环,但我一直想知道是否有更接近惯用的方法来做。它是Python;我不应该以某种巧妙的方式使用迭代器吗?简单地在索引上循环似乎很清楚,但我想知道是否有一种更具表现力或简洁的方法来实现它

for revindex in xrange(len(dm_revisions) - 1):
    summary = \
        svn.diff_summarize(svn_path,
                          revision1=dm_revisions[revindex],
                          revision2 = dm_revisions[revindex+1])

将上一个值存储在变量中。使用在处理序列中不太可能找到的值初始化变量,以便知道是否在第一个元素处。将旧值与当前值进行比较。

我可能会:

import itertools
for rev1, rev2 in zip(dm_revisions, itertools.islice(dm_revisions, 1, None)):
    summary = svn.diff_sumeraize(svn_python, revision1=rev, revision2=rev2)

如果您注意在Reduce函数的结果中保留当前项的副本,则可以使用

Reduce来完成类似的更聪明的操作,并且不触及迭代器本身

EDIT:是,但是没有人说
reduce
中函数的结果必须是标量。我改变了我的示例,使用列表。基本上,最后一个元素始终是以前的版本(第一次通过时除外),前面的所有元素都是
svn.diff\u summary
调用的结果。这样,您将得到一个结果列表作为最终输出

EDIT2:是的,代码确实被破坏了。我这里有一个可行的假人:

>>> def compare(lst, nxt):
...    if lst:
...       prev = lst.pop()
...       lst.append((prev, nxt))
...    lst.append(nxt)
...    return lst
...
>>> reduce(compare, "abcdefg", [])
[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e'), ('e', 'f'), ('f', 'g'), 'g']
正如您所见,这是在shell中测试的。您需要在
lst.append
调用
compare
中替换
(prev,nxt)
,以将调用的摘要实际附加到
svn.diff\u summary

>>> help(reduce)
Help on built-in function reduce in module __builtin__:

reduce(...)
    reduce(function, sequence[, initial]) -> value

    Apply a function of two arguments cumulatively to the items of a sequence,
    from left to right, so as to reduce the sequence to a single value.
    For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
    ((((1+2)+3)+4)+5).  If initial is present, it is placed before the items
    of the sequence in the calculation, and serves as a default when the
    sequence is empty.

这称为滑动窗口。有一个能做到这一点的。代码如下:

from itertools import islice

def window(seq, n=2):
    "Returns a sliding window (of width n) over data from the iterable"
    "   s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...                   "
    it = iter(seq)
    result = tuple(islice(it, n))
    if len(result) == n:
        yield result    
    for elem in it:
        result = result[1:] + (elem,)
        yield result
你可以这样说:

for r1, r2 in window(dm_revisions):
    summary = svn.diff_summarize(svn_path, revision1=r1, revision2=r2)
当然,您只关心n=2的情况,因此您可以使用更简单的方法:

def adjacent_pairs(seq):
    it = iter(seq)
    a = it.next()
    for b in it:
        yield a, b
        a = b

for r1, r2 in adjacent_pairs(dm_revisions):
    summary = svn.diff_summarize(svn_path, revision1=r1, revision2=r2)

发布了这么多复杂的解决方案,为什么不保持简单呢

myList = range(5)

for idx, item1 in enumerate(myList[:-1]):
    item2 = L[idx + 1]
    print item1, item2

>>> 
0 1
1 2
2 3
3 4

这是我想到的第一件事,它是更实用的方法。实际上,您正在使用“其余部分”本身压缩列表(结果是v1、v2、v2、v3、v3…),然后从结果列表(v1、v2)(v2、v3)(v3、v4)中取出两对……这很有意义,而且看起来相当简洁。使用izip怎么样,如下所述:?不,reduce将函数应用于序列中的每个元素以及到目前为止累积的reduce值,而不是将其应用于每个元素及其前身。我相信OP只是想比较连续的元素。reduce所做的是对前两个元素进行操作,获取结果,并使用结果和下一个元素执行操作,然后重复此操作,直到没有剩下任何元素。当然,但这只是略有不同-您仍然在将一次迭代的数据与下一次迭代的数据进行比较。请参阅更新的代码。该代码非常糟糕,看起来像。您可以使用reduce实现这一点:但我不推荐它。它似乎不必要地不透明。就我个人而言,我觉得实际上可能存在更聪明的方法来做到这一点,但循环索引是最清晰的方法。对于导致我找到解决方案的良好描述,+1。我看到较新的itertools文档在Recipes部分()中有一个“成对”函数。看起来它也会做同样的事情,是吗?是的。(谢天谢地,我们有15个字符的限制。否则我只能回答“是”或“否”的问题。)太好了。这是有效的,而且我认为更清楚。我可以给这些修订提供信息性的名称,这样人们就知道在脚本的下面使用了什么。我也很高兴看到所有这些都被详细说明,即使我最终使用了“tee”和“izip”。啊,这听起来像是一种有趣的替代方法——虽然不像创建一个奇特的成对迭代器那样通俗:)事实上,一个奇特的成对迭代器会更Haskellish/Lispish,尽管它在Python中工作。有趣;我想我还有更多关于这三种表达方式的知识要学。
myList = range(5)

for idx, item1 in enumerate(myList[:-1]):
    item2 = L[idx + 1]
    print item1, item2

>>> 
0 1
1 2
2 3
3 4