Question

This is a problem I've come across a lot lately. Google doesn't seem to have an answer so I bring it to the good people of stack overflow.

I am looking for a simple way to populate a list with the output of a function. Something like this:

fill(random.random(), 3) #=> [0.04095623, 0.39761869, 0.46227642]

Here are other ways I've found to do this. But I'm not really happy with them, as they seem inefficient.

results = []
for x in xrange(3): results.append(random.random())
#results => [0.04095623, 0.39761869, 0.46227642]

and

map(lambda x: random.random(), [None] * 3)
#=> [0.04095623, 0.39761869, 0.46227642]

Suggestions?


Thanks for all the answers. I knew there was a more python-esque way.

And to the efficiency questions...

$ python --version
Python 2.7.1+
$ python -m timeit "import random" "map(lambda x: random.random(), [None] * 3)"
1000000 loops, best of 3: 1.65 usec per loop
$ python -m timeit "import random" "results = []" "for x in xrange(3): results.append(random.random())"
1000000 loops, best of 3: 1.41 usec per loop
$ python -m timeit "import random" "[random.random() for x in xrange(3)]"
1000000 loops, best of 3: 1.09 usec per loop
Was it helpful?

Solution

How about a list comprehension?

[random.random() for x in xrange(3)]

Also, in many cases, you need the values just once. In these cases, a generator expression which computes the values just-in-time and does not require a memory allocation is preferable:

results = (random.random() for x in xrange(3))
for r in results:
   ...
# results is "used up" now.
# We could have used results_list = list(results) to convert the generator

By the way, in Python 3.x, xrange has been replaced by range. In Python 2.x, range allocates the memory and calculates all values beforehand (like a list comprehension), whereas xrange calculates the values just-in-time and does not allocate memory (it's a generator).

OTHER TIPS

why do you think they are inefficient?

There is another way to do it,a list-comprehension

listt= [random.random() for i in range(3)]

something more generic...

from random import random

fill = lambda func, num: [func() for x in xrange(num)]
# for generating tuples:
fill = lambda func, num: (func() for x in xrange(num))


# then just call:
fill(random, 4)
# or...
fill(lambda : 1+2*random(), 4)
   list =  [random.random() for i in xrange(3)]
   list =  [random.random() for i in [0]*3]
   list =  [i() for i in [random.random]*3]

Or :

  fill =lambda f,n: [f() for i in xrange(n)]
  fill(random.random , 3 ) #=> [0.04095623, 0.39761869, 0.46227642]

List comprehension is probably clearest, but for the itertools afficionado:

>>> list(itertools.islice(iter(random.random, None), 3))
[0.42565379345946064, 0.41754360645917354, 0.797286438646947]

A quick check with timeit shows that the itertools version is ever so slightly faster for more than 10 items, but still go with whatever seems clearest to you:

C:\Python32>python lib\timeit.py -s "import random, itertools" "list(itertools.islice(iter(random.random, None), 10))"
100000 loops, best of 3: 2.93 usec per loop

C:\Python32>python lib\timeit.py -s "import random, itertools" "[random.random() for _ in range(10)]"
100000 loops, best of 3: 3.19 usec per loop
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top