|
|
 |
|
Title: Parallel loop on index and sequence-item
Submitter: Alex Martelli
(other recipes)
Last Updated: 2001/07/04
Version no: 1.2
Category:
|
|
6 vote(s)
|
|
|
|
Description:
zip() stops zipping at the shortest of its sequence-arguments and thus also allows unbounded-sequence arguments. This affords, for example, a very spare idiom for the frequent need of a parallel loop on index and sequence-item.
Source: Text Source
indices = xrange(sys.maxint)
for item, index in zip(sequence, indices):
something(item, index)
for index in range(len(sequence)):
something(sequence[index], index)
class Indexed:
def __init__(self, seq):
self.seq = seq
def __getitem__(self, i):
return self.seq[i], i
for item, index in Indexed(sequence):
something(item, index)
def Indexed(sequence):
return zip(sequence, indices)
Discussion:
We often want to loop on a sequence, but also need the current index in the loop body. Canonical is "for i in range(len(sequence)):", using sequence[i] as the item-reference in the body. But in some contexts it's clearer to emphasise the loop on the sequence-item rather than on the index. zip gives an easy alternative, looping on both index and item in parallel, since it truncates at the _shortest_ of its arguments -- thus, it's OK for some arguments to be unbounded sequences. An unbounded sequence of indices is trivial to write (xrange is handy for this!) and a (reusable...) instance of that can be passed to zip, in parallel to the sequence being indexed.
The same zip usage also affords a client-code-transparent alternative to the use of a wrapper-class 'Indexed' -- see the Indexed class and function in the above example code.
|
|
Add comment
|
|
Number of comments: 4
zip() not semantically equivalent, Sami Hangaslammi,Sami Hangaslammi, 2001/07/09
Sometimes using zip() will provide different results (with some lazily evaluted sequences) or fail (with unbounded sequences).
Since we already have xrange and xreadlines, maybe someone should do a PEP on xfilter, xmap and xzip too. ;-)
Add comment
so just use the Class, Phillip Ruggera, 2005/01/11
map is also going to be depreciated in 3.0. So use the Class:
>>> class Indexed(object):
... def __init__(self, seq):
... self.seq = seq
... def __getitem__(self, i):
... return self.seq[i], i
>>> sequence = ['a','b','c','d','e','f']
>>> for item, index in Indexed(sequence):
... print item, str(index)
a 0
b 1
c 2
d 3
e 4
f 5
Add comment
An iterable version, Phillip Ruggera, 2005/01/12
Since almost all objects are iterable now we can enhance the class to work with them:
class Indexed(object):
"""provide index while iterating over an object
>>> sequence = ['a','b','c','d','e','f']
>>> for item, index in Indexed(sequence):
... print item, str(index)
a 0
b 1
c 2
d 3
e 4
f 5
"""
def __init__(self, object):
self.object = object.__iter__()
def __getitem__(self, i):
return self.object.next(), i
Add comment
Builtin with 2.3, Phillip Ruggera, 2005/01/13
There is a builtin that provides the same functionality as the class:
>>> sequence = ['a','b','c','d','e','f']
>>> for index, item in enumerate(sequence):
... print index, item
...
0 a
1 b
2 c
3 d
4 e
5 f
I need to read the fine manuals more often.
Add comment
|
|
|
|
|
 |
|