简体   繁体   English

Python循环:以惯用方式比较列表中的连续项

[英]Python looping: idiomatically comparing successive items in a list

I need to loop over a list of objects, comparing them like this: 0 vs. 1, 1 vs. 2, 2 vs. 3, etc. (I'm using pysvn to extract a list of diffs.) I wound up just looping over an index, but I keep wondering if there's some way to do it which is more closely idiomatic. 我需要循环一个对象列表,比较它们是这样的:0对1,1对2,2对3等等(我正在使用pysvn来提取差异列表。)我结束了循环索引,但我一直想知道是否有某种方法可以做到更贴近惯用。 It's Python; 这是Python; shouldn't I be using iterators in some clever way? 我不应该以某种聪明的方式使用迭代器吗? Simply looping over the index seems pretty clear, but I wonder if there's a more expressive or concise way to do it. 简单地循环索引似乎很清楚,但我想知道是否有更具表现力或简洁的方法来做到这一点。

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

This is called a sliding window. 这称为滑动窗口。 There's an example in the itertools documentation that does it. itertools文档中有一个例子可以做到这一点。 Here's the code: 这是代码:

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

What that, you can say this: 那是什么,你可以这样说:

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

Of course you only care about the case where n=2, so you can get away with something much simpler: 当然你只关心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)

I'd probably do: 我可能会这样做:

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)

Something similarly cleverer and not touching the iterators themselves could probably be done using 类似地更聪明并且不接触迭代器本身的东西可能可以使用

So many complex solutions posted, why not keep it simple? 发布了如此多的复杂解决方案,为什么不保持简单?

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

Store the previous value in a variable. 将先前的值存储在变量中。 Initialize the variable with a value you're not likely to find in the sequence you're handling, so you can know if you're at the first element. 使用您在处理的序列中找不到的值初始化变量,这样您就可以知道您是否处于第一个元素。 Compare the old value to the current value. 将旧值与当前值进行比较。

Reduce can be used for this purpose, if you take care to leave a copy of the current item in the result of the reducing function . 如果您注意在还原功能的结果中保留当前项目的副本 ,则可以将Reduce用于此目的。

def diff_summarize(revisionList, nextRevision):
    '''helper function (adaptor) for using svn.diff_summarize with reduce'''
    if revisionList:
        # remove the previously tacked on item
        r1 = revisionList.pop()
        revisionList.append(svn.diff_summarize(
            svn_path, revision1=r1, revision2=nextRevision))
    # tack the current item onto the end of the list for use in next iteration
    revisionList.append(nextRevision)
    return revisionList

summaries = reduce(diff_summarize, dm_revisions, [])

EDIT: Yes, but nobody said the result of the function in reduce has to be scalar. 编辑:是的,但没有人说reduce函数的结果必须是标量。 I changed my example to use a list. 我改变了我的例子以使用列表。 Basically, the last element is allways the previous revision (except on first pass), with all preceding elements being the results of the svn.diff_summarize call. 基本上,最后一个元素是前一个修订版(第一遍除外),所有前面的元素都是svn.diff_summarize调用的结果。 This way, you get a list of results as your final output... 这样,您可以获得结果列表作为最终输出...

EDIT2: Yep, the code really was broken. EDIT2:是的 ,代码真的坏了。 I have here a workable dummy: 我这里有一个可行的假人:

>>> 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']

This was tested in the shell, as you can see. 正如您所看到的,这在shell中进行了测试。 You will want to replace (prev, nxt) in the lst.append call of compare to actually append the summary of the call to svn.diff_summarize . 您将需要在comparelst.append调用中替换(prev, nxt)以实际将调用的摘要附加到svn.diff_summarize

>>> 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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM