Newbie: list comprehension troubles..

M

mm

Hi, I'm trying to replace this...

# this works but there must be a more pythonic way, right?
tlist = []
for obj in self.objs:
t = obj.intersect(ray)
if (t != None):
tlist.append((obj,t))

with a list comprehension- can it be done?

What I need to do is iterate over a list of graphics primitives and
call their intersect method. If the returned t value is not None then
I want to store the obj refernence and its t value in a list of tuples
for further processing. I've tried stuff like ...

tlist = [(obj,t) for obj,t in (self.objs, obj.intersect(ray))
if (t != None)]
tlist = [(obj,t) for obj in self.objs for t in obj.intersect
(ray) ]
print ">>> ",len(tlist), tlist

but they don't work. Any help greatly appreciated. matt
 
C

Chris Rebert

Hi, I'm trying to replace this...

       # this works but there must be a more pythonic way, right?
       tlist = []
       for obj in self.objs:
           t = obj.intersect(ray)
           if (t != None):
               tlist.append((obj,t))

with a list comprehension- can it be done?

Yes:
tlist = [pair for pair in ((obj, obj.intersect(ray)) for obj in
self.objs) if pair[1] is not None]

Should it be done? Probably not. It's less readable and less efficient.

Cheers,
Chris
 
T

Terry Reedy

'Pythonic' is readable, if nothing else
tlist = []
for obj in self.objs:
t = obj.intersect(ray)
if (t != None):
tlist.append((obj,t))

This, to me, is more readable than the lc replacement.
with a list comprehension- can it be done?

Yes:
tlist = [pair for pair in ((obj, obj.intersect(ray)) for obj in
self.objs) if pair[1] is not None]

Should it be done? Probably not. It's less readable and less efficient.

I agree.

tjr
 
C

Chris Rebert

Chris Rebert said:
tlist = [pair for pair in ((obj, obj.intersect(ray)) for obj in
self.objs) if pair[1] is not None]

Should it be done? Probably not. [Compared to a ‘for’ suite with an
‘if’ suite, it's] less readable and less efficient.

I disagree on the “less efficientâ€, unless you've measured it. The
Python compiler and machine make list comprehensions and generator
expressions turn into quite efficient code.

Well, I hadn't benchmarked it originally, but since you bring it up:

class Foo(object):
def __init__(self, n):
self.n = n
def intersect(self, ray):
return ray + self.n

objs = [Foo(n) for n in range(300)]
ray = 42


def listcomp(objs, ray):
tlist = [pair for pair in ((obj, obj.intersect(ray)) for obj in
objs) if pair[1] is not None]

def naive(objs, ray):
tlist = []
for obj in objs:
t = obj.intersect(ray)
if t is not None:
tlist.append((obj,t))

chris@morpheus Desktop $ python
Python 2.6.2 (r262:71600, May 14 2009, 16:34:51)
[GCC 4.0.1 (Apple Inc. build 5484)] on darwin
chris@morpheus Desktop $ python -m timeit -n 10000 -s 'from tmp import
naive, ray, objs' 'naive(objs, ray)'
10000 loops, best of 3: 227 usec per loop
chris@morpheus Desktop $ python -m timeit -n 10000 -s 'from tmp import
listcomp, ray, objs' 'listcomp(objs, ray)'
10000 loops, best of 3: 254 usec per loop

The numbers for each test stayed within a few usec of each other over
a few runs. I thus conclude that the list comprehension method is
indeed slower (which makes sense looking at the 2 algorithms).
I also disagree on “less readableâ€, if you show the structure and choose
meaningful names (I can only guess at the meaning from the OP's code)::

   tribbles = [
       (obj, tribble) for (obj, tribble) in (
           (obj, obj.intersect(ray))
           for obj in self.objs)
       if tribble is not None]

I do concede it becomes somewhat more readable if split over multiple lines:

pairs = ((obj, obj.intersect(ray)) for obj in self.objs)
tlist = [pair for pair in pairs if pair[1] is not None]

Cheers,
Chris
 
B

Bruno Desthuilliers

mm a écrit :
Hi, I'm trying to replace this...

# this works but there must be a more pythonic way, right?
tlist = []
for obj in self.objs:
t = obj.intersect(ray)
if (t != None):

hint 1 : this is Python, you don't need parens around conditionals.
hint 2 : None is a singleton, so the usual idiom is to test for identity
('is') instead of equality ('==')

IOW, make this line:

if t is not None:
tlist.append((obj,t))

with a list comprehension- can it be done?

See other answers here. As far as I'm concerned, while being a great fan
of list comps etc, I'd stick with the plain old for loop here - much
more readable if nothing else.
 
F

Francesco Bochicchio

Hi, I'm trying to replace this...

        # this works but there must be a more pythonic way, right?
        tlist = []
        for obj in self.objs:
            t = obj.intersect(ray)
            if (t != None):
                tlist.append((obj,t))

with a list comprehension- can it be done?

What I need to do is iterate over a list of graphics primitives and
call their intersect method. If the returned t value is not None then
I want to store the obj refernence and its t value in a list of tuples
for further processing. I've tried stuff like ...

        tlist = [(obj,t) for obj,t in (self.objs, obj.intersect(ray))
if (t != None)]
        tlist = [(obj,t) for obj in self.objs for t in obj.intersect
(ray) ]
        print ">>> ",len(tlist), tlist

but they don't work. Any help greatly appreciated. matt

What about this:

def intersections(objlist, ray):
for obj in objlist: yield obj, obj.intersect(ray)
tlist = [(obj, t) in intersections(self.objs, ray) if t != None ]

It is still quite readable but a bit more compact. More efficient?
Maybe.

Ciao
 

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,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top