for (i = n; i--; )
and I wouldn't say this idiom is that clear. You can get used to it, of course. Another interesting case is printing a list of items with separators. C loop constructs are biased cases of frequently used loops but they do not cover all the possible cases. 'goto' is unbiased.A similar case are Python loops. There are “Pythonic” ways:
for item in iterable
...
They look sweet but are useful only in some cases. E.g. if you need to modify `iterable`, the Pythonic way won’t work. There are Pythonic workarounds, but they may involve copying a whole iterable, which is hardly a good idea. But there is also a less Pythonic way: i = 0; n = len(iterable)
while i < n:
...
This works all the time and serves all possible cases. for i in range(len(iterable)):
... for i, item in enumerate(iterable):
...With an integer cursor (`i`) there are no unique numbers for each item and no temporary tuples. This is slightly cheaper. And also more flexible, which is the main point I'm trying to make. Other loop constructs are meant to be used in certain way and will not work otherwise. Integer cursors are not meant to be used in any special way, you can combine them as you wish. They give the maximum possible flexibility from the beginning. You can loop in any direction, by multiple items or by a variable number of items, over many iterables at once, changing the iterables as you go, and so on.
(A special case in Python are list comprehensions; these are useful because most of that “comprehending” happens inside CPython and thus they are faster.)
squared = (x*x for x in iterable)
In general, a generator function can be used if necessary: def squared(iterable):
for x in iterable:
yield x*xThese kinds of choice don't come alone, but together with the 'step' keyword, the opiniated absence of the 'continue' keyword and the availability or inner/embedded functions/procedures.
For me classic foreach iterators that mask the actual iterator fall apart when I need some kind of 'join' operation (do something specific on each first, last and neither elements of a collection).
Unless you want the check to be always against the initial length of your iterable, rather than its modified state, you'd have to repeat the `n = len(iterable)` inside the loop, or introduce some syntactic caramel of the walrus kind (though I'm not sure if it would work here).
while i < n:
if shouldDelete(iterable[i]):
del iterable[i]; n -= 1
else:
i += 1