Reputation: 3343
The python syntax of for x in y:
to iterate over a list must somehow remember what element the pointer is at currently right? How would we access that value as I am trying to solve this without resorting to for index, x in enumerate(y):
The technical reason why I want to do this is that I assume that enumerate()
costs performance while somehow accessing the 'pointer' which is already existing would not. I see that from the answers however this pointer is quite private and inaccessible however.
The functional reason why I wanted to do this is to be able to skip for instance 100 elements if the current element float value is far off from the 'desired' float range.
-- Answer --
The way this was solved was as follows (pure schematic example):
# foo is assumed to be ordered in this example
foo = [1,2,3,4,5,6....,99,100]
low = 60
high = 70
z = iter(foo)
for x in z:
if x < low-10
next(islice(z,10,10),None)
if x > high
break
Upvotes: 0
Views: 252
Reputation: 39926
No, it uses the underlying iterator, which is not forced to keep track of a current index.
Unless you manually incerement a counter, this is not possible:
idx = 0
for x in y:
idx+=1
# ...
so, just keep with enumerate()
Upvotes: 1
Reputation: 1124100
You cannot. for
uses the Python iteration protocol, which for lists means it'll create a private iterator object. That object keeps track of the position in the list.
Even if you were to create the iterator explicitly with iter()
, the current position is not a public property on that object:
>>> list_iter = iter([])
>>> list_iter
<listiterator object at 0x10056a990>
>>> dir(list_iter)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__length_hint__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'next']
The point of the iteration protocol is that it lets you treat any sequence, even one that continues without bounds, in exactly the same way. It is trivial to create a sequence generator that does not have a position:
def toggle():
while True:
yield True
yield False
That generator will toggle between True
and False
values as you iterate over it. There is no position in a sequence there, so there is no point exposing a position either.
Just stick to enumerate()
. All that enumerate()
has to do is keep a counter. It doesn't keep position in the wrapped iterator at all. Incrementing that integer does not cost you much performance or memory.
enumerate()
is basically this, implemented in C:
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1
Because it is implemented in C, it'll beat trying to read an attribute on the original iterator any day, which would require more bytecode operations in each iteration.
Upvotes: 7
Reputation: 26381
This information is internal to the iterator and cannot be accessed. See here for a description of the iterator protocol. Essentially, the only publicly available member of the iterator is next()
which raises a StopIteration
exception once the range is exhausted.
Besides, enumerate
is pretty efficient. It is the equivalent of writing
i = -1
for x in y:
i += 1
# do something with x and i
Upvotes: 1
Reputation: 9231
That 'pointer' value is internal to whatever it is that created the iterator. Remember that is doesn't need to be a list (something that can be indexed), so if you really want the 'index', you will need to resort to using enumerate.
Upvotes: 1