i=2; lst=[i**=2 while i<1000]

  • Thread starter =?ISO-8859-1?Q?Daniel_Sch=FCle?=
  • Start date
S

Sion Arrowsmith

Bengt said:
list(iter(lambda b=[2]:b.append(b[0]**2) or b[0]<1000 and b.pop(0) or None, None))
[2, 4, 16, 256]
out of curiosity, what stops the iterator ?

<http://docs.python.org/lib/built-in-funcs.html>:

iter(o, sentinel) [ ... ]
The iterator created in this case will call o with no arguments for
each call to its next() method; if the value returned is equal to
sentinel, StopIteration will be raised, otherwise the value will be
returned.

In this case, o is:

lambda b=[2]:b.append(b[0]**2) or b[0]<1000 and b.pop(0) or None

which returns None when b[0]>=1000 (None or (False and _) or None
evaluates to the last None).
 
M

Michael Spencer

Daniel said:
Hello NG,

I am wondering if there were proposals or previous disscussions in this
NG considering using 'while' in comprehension lists

# pseudo code
i=2
lst=[i**=2 while i<1000]

You are actually describing two features that list comps don't natively support
- while-based termination, and calculating based on prior values of output. Of
course there are work-arounds for both, which others have shown. Here's another
approach:

The while-based termination can be easily achieved using itertools.takewhile, e.g.,:
>>> list(itertools.takewhile(lambda x: x < 10, range(100))) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>

the harder piece is to access the prior value. One way is like this:

def chasetail(start, func):
from itertools import tee
def mygen():
yield start
for i in (func(i) for i in iterators[0]):
yield i
iterators = tee(mygen())
return iterators[1]

the trick is to create two independent iterators, using itertools.tee, one of
which is consumed internally in the func(i) for i in iterators[0] generator
expression, the other is returned to use code.

Then you can combine these two approaches to get something semantically like
what you wanted in the first place (although not as pretty ;-)
>>> list(itertools.takewhile(lambda x: x < 1000, chasetail(2, lambda x: x*x))) [2, 4, 16, 256]
>>>



If you like this sort of thing, you might want to generalize the concept with a
Stream class. Here's minimal implementation:

import itertools as it

class Stream(object):
"""An extendable stream, that provides a separate iterator
(using itertools.tee) on every iteration request"""

def __init__(self, *iterables):
self.queue = list(iterables)
self.itertee = it.tee(self._chain(self.queue))[0]

def _chain(self, queue):
while queue:
for i in self.queue.pop(0):
self.head = i
yield i

def extend(self,other):
self.queue.append(other)

def __iter__(self):
"""Normal iteration over the iterables in self.queue in turn"""
return self.itertee.__copy__()


then, you can write your squaring algorithm as:
>>> s= Stream([2])
>>> s.extend(it.takewhile(lambda x: x < 1000, (i**2 for i in s)))
>>> list(s)
[2, 4, 16, 256]


Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top