Is there an expression for an infinite iterator?
for x in iter(int, 1): pass
- Two-argument
iter
= zero-argument callable + sentinel value int()
always returns0
Therefore, iter(int, 1)
is an infinite iterator. There are obviously a huge number of variations on this particular theme (especially once you add lambda
into the mix). One variant of particular note is iter(f, object())
, as using a freshly created object as the sentinel value almost guarantees an infinite iterator regardless of the callable used as the first argument.
combine infinite with finite iterator
You can create a generator using a comprehension. Comprehensions support iterating over multiple iterables at once using multiple for
s
for j, q in ((j, q) for j in itertools.count() for q in Q):
...
How to create an infinite iterator to generate an incrementing alphabet pattern?
Yield column_names
's last element every time, and use itertools.count
instead of range
to provide infinite increase:
import itertools
def _column_name_generator():
column_names = []
for x in itertools.count():
if x < 26:
column_names.append(string.ascii_uppercase[x % 26])
else:
column_names.append(column_names[x/26 - 1] + string.ascii_uppercase[x % 26])
yield column_names[-1]
A better solution, altering the original code but dismissing the need in a memory consuming list of column_names
, would be
import itertools, string
def _column_name_generator():
for i in itertools.count(1):
for p in itertools.product(string.ascii_uppercase, repeat=i):
yield ''.join(p)
it basically iterates over the product of length i
the uppercase ascii letters (every sequence possible) when i is gradually increasing, starting from 1
(A
, B
, C
).
Infinite loops using 'for' in Python
range
is a class, and using in like e.g. range(1, a)
creates an object of that class. This object is created only once, it is not recreated every iteration of the loop. That's the reason the first example will not result in an infinite loop.
The other two loops are not infinite because, unlike the range
object, the loop variable i
is recreated (or rather reinitialized) each iteration. The values you assign to i
inside the loop will be overwritten as the loop iterates.
Looping from 1 to infinity in Python
Using itertools.count
:
import itertools
for i in itertools.count(start=1):
if there_is_a_reason_to_break(i):
break
In Python 2, range()
and xrange()
were limited to sys.maxsize
. In Python 3 range()
can go much higher, though not to infinity:
import sys
for i in range(sys.maxsize**10): # you could go even higher if you really want
if there_is_a_reason_to_break(i):
break
So it's probably best to use count()
.
How to stop an infinite iterator on the first None value?
flat_map()
is the wrong tool for this task. It is designed to flatten an iterator of iterators, i.e. whenever it encounters None
on an inner iterator, its job is to switch to the next iterator. If you keep feeding it empty iterators, it will keep looping until it finds a non-empty one to deliver values from. flat_map()
will only terminate iteration when the outer iterator does, which in your case never happens.
What you need is two things: first, mark the end of iteration in some way other than an empty iterator - e.g. by using an Option
where Some
means "here is another iterator for you" and None
means "I'm no longer interested in iteration, you can terminate". Second, you need to terminate the iteration before the flattening step, using an adapter with the capacity to do so, such as take_while()
or scan()
.
Here is a modification of your code that terminates after i
reaches 10:
fn main() {
let iter = (0..)
.map(move |i| if i < 10 { Some(0..i) } else { None })
.scan((), |_, item| item)
.flatten();
for i in iter {
println!("{}", i);
}
}
Playground
Here the flat_map()
is broken into three parts: first a map()
that produces Some(inner_iterator)
while we want to iterate, and None
when we no longer do. Then comes scan()
that transforms the iterator into one whose next()
just returns the values returned by the closure. Since the closure returns item
(inner iterator wrapped in an option) unchanged, Some(inner_iterator)
will pass through, and None
will be propagated as the end-of-iteration signal. Finally, flatten()
funnels the items produced by inner iterators into a single iterator, as flat_map()
did in your original code.
And if you really want to terminate on the first inner iterator that is empty, that can be arranged as well, by extracting the first value in scan()
and testing it:
// using 1.. to avoid immediately terminating on 0..0
let iter = (1..)
.map(move |i| if i < 10 { 0..i } else { 0..0 })
.scan((), |_, mut inner| match inner.next() {
Some(first) => Some(once(first).chain(inner)),
None => None,
})
.flatten();
Playground
Note that fuse()
is not what you want in any of this. Its purpose is to allow the iterator to be safely queried after exhaustion. Normally an iterator could panic if you call next()
after it has already returned None
. fuse()
extends the iterator contract to allow calling next()
after it has already returned None
. This is implemented with a separate flag along the inner iterator, and a check of that flag in next()
. If you don't query the iterator after it has returned None
—which a for
loop doesn't—then you have no need for fuse()
.
Related Topics
How to Create a Spinning Command Line Cursor
How to Get Stable Results with Tensorflow, Setting Random Seed
How to Set Ticks on Fixed Position , Matplotlib
How to Use Valgrind with Python
How to Loop Through a List by Twos
Redirect While Passing Arguments
Activate Python Virtualenv in Dockerfile
Typeerror: 'List' Object Is Not Callable While Trying to Access a List
Panda's Dataframe - Renaming Multiple Identically Named Columns
What's the Difference Between 'R+' and 'A+' When Open File in Python
Convert from Ascii String Encoded in Hex to Plain Ascii
Get Class Labels from Keras Functional Model
Qwidget Does Not Draw Background Color
I'm Getting "Typeerror: 'List' Object Is Not Callable". How to Fix This Error