16

I have a list of objects:

[Object_1, Object_2, Object_3]

Each object has an attribute: time:

Object_1.time = 20
Object_2.time = 30
Object_3.time = 40

I want to create a list of the time attributes:

[20, 30, 40]

What is the most efficient way to get this output? It can't be to iterate over the object list, right?:

items = []
for item in objects:
    items.append(item.time)
6
  • 'efficient' is in the eye of the beholder... Commented Jun 19, 2012 at 1:58
  • 2
    @Pyson: No it isn't, "efficient" is measured in complexity, computation time, lines of code and/or memory usage. Commented Jun 19, 2012 at 2:01
  • 4
    @Junuxx: most people do not test each and every instance of a comprehension vs a loop to see which is fewer CPU cycles. If you are using Python, it is probably about ease to write and read -- not absolute speed. What you stated there, computation time, lines of code and/or memory usage, may be completely at odds with each other. Double the code may be faster and use less memory, but takes more time to read and write as a programmer. Which is more efficient? Faster to execute or faster to write in Python? This is my point. Commented Jun 19, 2012 at 2:05
  • @Pyson: Right, that sounds much more reasonable. Still, there is always some objective measurement you could take to settle a discussion (if well-defined). Your initial comment sounded a bit like 'anything you do is fine' to me, but programming just isn't fine art. Commented Jun 19, 2012 at 2:13
  • 1
    A list comprehension is faster in all cases, execution, reading, writing. There is no debate that it is the best solution in this case. Commented Jun 19, 2012 at 2:23

4 Answers 4

37

List comprehension is what you're after:

list_of_objects = [Object_1, Object_2, Object_3]
[x.time for x in list_of_objects]
Sign up to request clarification or add additional context in comments.

13 Comments

@Marcin: Actually, it's not guaranteed anywhere that list comprehensions are either equally, more, or less efficient than the equivalent list. Sure, you can figure out the answer by reading the CPython code (or the mailing list threads from when list comprehensions were proposed), but can you assume that would apply to, say, PyPy? So, a better thing to say is that there's no good reason to believe this will be more efficient.
What? Yes, there is. A list comprehension loop is done C-side, which is significantly faster than a Python loop. Any implementation will be faster as a list comprehension is a less expressive thing, and so can be optimised more efficiently.
As I explained, yes. A list comprehension is less expressive than a normal Python loop - a normal Python loop cannot make assumptions that a list comprehension can, meaning it is easy to make a list comprehension more efficient than a loop. In all implementations a list comprehension will be the preferred option. (Never mind the fact it is more readable, which should be the primary concern).
@abarnert even in PyPy and Jython, it isn't at all far fetched to say that using a provided high-level construct lets the implementation optimise it better than writing out the equivalent lower-level code yourself. It isn't done in C everywhere, but it is done in - to use the more general PyPy terminology - system-level code rather than app-level code.
It's like arguing you shouldn't use str.join() because, potentially, someone could implement it as a series of string concatenations. While true, it's insane to suggest that it means you should not use str.join(). You can't spend your life second-guessing the implementation and assuming it has been implemented in the worst way humanly possible.
|
4
from operator import attrgetter
items = map(attrgetter('time'), objects)

2 Comments

Note that map returns a generator, not a list in 3.x, and that a list comprehension is far more readable (and probably faster) for something like this.
@Lattyware: +1. And if you actually want a generator, you can use a generator expression just as easily as a list comprehension.
2

How about:

items=[item.time for item in objects]

Comments

2

The fastest (and easiest to understand) is with a list comprehension.

See the timing:

import timeit
import random
c=10000

class SomeObj:
    def __init__(self, i):
        self.attr=i

def loopCR():
    l=[]
    for i in range(c):
        l.append(SomeObj(random.random()))

    return l 

def compCR():
    return [SomeObj(random.random()) for i in range(c)]   

def loopAc():
    lAttr=[]
    for e in l:
        lAttr.append(e.attr)

    return lAttr

def compAc():
    return [e.attr for e in l]             

t1=timeit.Timer(loopCR).timeit(10)
t2=timeit.Timer(compCR).timeit(10)
print "loop create:", t1,"secs"   
print "comprehension create:", t2,"secs"   
print 'Faster of those is', 100.0*abs(t1-t2) / max(t1,t2), '% faster'
print 

l=compCR()

t1=timeit.Timer(loopAc).timeit(10)
t2=timeit.Timer(compAc).timeit(10)
print "loop access:", t1,"secs"   
print "comprehension access:", t2,"secs"   
print 'Faster of those is', 100.0*abs(t1-t2) / max(t1,t2), '% faster'

Prints:

loop create: 0.103852987289 secs
comprehension create: 0.0848100185394 secs
Faster of those is 18.3364670069 % faster

loop access: 0.0206878185272 secs
comprehension access: 0.00913000106812 secs
Faster of those is 55.8677438315 % faster

So list comprehension is both faster to write and faster to execute.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.