Loops Python循环:习惯性地比较列表中的连续项
我需要在一个对象列表上循环,像这样比较它们:0对1,1对2,2对3,等等(我使用pysvn提取一个差异列表)。我只是在一个索引上循环,但我一直想知道是否有更接近惯用的方法来做。它是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
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