(In Python 3.1) (Somewhat related to another question I asked, but this question is about iterators being exhausted.)
# trying to see the ratio of the max and min element in a container c
filtered = filter(lambda x : x is not None and x != 0, c)
ratio = max(filtered) / min(filtered)
It took me half hour to realize what the problem is (the iterator returned by filter is exhausted by the time it gets to the second function call). How do I rewrite it in the most Pythonic / canonical way?
Also, what can I do to avoid bugs of this sort, besides getting more experience? (Frankly, I don't like this language feature, since these types of bugs are easy to make and hard to catch.)
Iterators will be faster and have better memory efficiency. Just think of an example of range(1000) vs xrange(1000) . (This has been changed in 3.0, range is now an iterator.) With range you pre-build your list, but xrange is an iterator and yields the next item when needed instead.
Note that every iterator is also an iterable, but not every iterable is an iterator. For example, a list is iterable but a list is not an iterator. An iterator can be created from an iterable by using the function iter().
Iterators are lazy Iterators allow us to both work with and create lazy iterables that don't do any work until we ask them for their next item.
C++ Iterators Reverse Iterators A reverse iterator is made from a bidirectional, or random access iterator which it keeps as a member which can be accessed through base() . To iterate backwards use rbegin() and rend() as the iterators for the end of the collection, and the start of the collection respectively.
The itertools.tee
function can help here:
import itertools
f1, f2 = itertools.tee(filtered, 2)
ratio = max(f1) / min(f2)
you can convert an iterator to a tuple simply by calling tuple(iterator)
however I'd rewrite that filter as a list comprehension, which would look something like this
# original
filtered = filter(lambda x : x is not None and x != 0, c)
# list comp
filtered = [x for x in c if x is not None and x != 0]
Actually your code raises an exception that would prevent this problem! So I guess the problem was that you masked the exception?
>>> min([])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence
>>> min(x for x in ())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence
Anyways, you can also write a new function to give you the min and max at the same time:
def minmax( seq ):
" returns the `(min, max)` of sequence `seq`"
it = iter(seq)
try:
min = max = next(it)
except StopIteration:
raise ValueError('arg is an empty sequence')
for item in it:
if item < min:
min = item
elif item > max:
max = item
return min, max
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With