Python loop: idiomatic comparison of sequential items in a list

I need to iterate over the list of objects, comparing them as follows: 0 versus 1, 1 versus 2, 2 versus 3, etc. (I use pysvn to retrieve the list of differences.) I just got stuck on the index, but I keep wondering if there is a way to do this, which is more closely idiomatic. This is Python; Shouldn't I use iterators in some smart way? The index loop just seems pretty clear, but I wonder if there is a more expressive or concise way of doing this.

for revindex in xrange(len(dm_revisions) - 1): summary = \ svn.diff_summarize(svn_path, revision1=dm_revisions[revindex], revision2 = dm_revisions[revindex+1]) 
+6
python iterator loops
source share
5 answers

This is called a sliding window. In this case, an example in the itertools documentation . Here is 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 is it, you can say the following:

 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:

 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) 
+13
source share

I would 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 similar is smarter and without touching the iterators themselves, perhaps one could do using

+4
source share

Many complex solutions have come up, why not just keep them 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 
+3
source share

Store the previous value in a variable. Initialize a variable with a value that you are unlikely to find in the sequence you are processing, so you can find out if you have the first element. Compare the old value with the current value.

0
source share

Reduction can be used for this purpose if you leave a copy of the current element as a result of the reduction function.

 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 no one said that the result of the function in reduce should be scalar. I changed my example to use a list. Basically, the last element is always the previous version (except the first), with all previous elements being the result of a call to svn.diff_summarize . This way you get a list of results as the final result ...

EDIT2: Yes, the code really was broken. I have a workable dummy here:

 >>> 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 has been verified in the shell, as you can see. You will want to replace (prev, nxt) with a call to lst.append compare to actually add a call summary to 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. 
-one
source share

All Articles