Go Back   Velocity Reviews > Newsgroups > Python
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

Reply

Python - Most efficient way to "pre-grow" a list?

 
Thread Tools Search this Thread
Old 11-06-2009, 12:12 PM   #1
Default Most efficient way to "pre-grow" a list?



In Perl one can assign a value to any element of an array, even to
ones corresponding to indices greater or equal than the length of
the array:

my @arr;
$arr[999] = 42;

perl grows the array as needed to accommodate this assignment. In
fact one common optimization in Perl is to "pre-grow" the array to
its final size, rather than having perl grow it piecemeal as required
by assignments like the one above:

my @arr;
$#arr = 999_999;

After assigning to $#arr (the last index of @arr) as shown above,
@arr has length 1,000,000, and all its elements are initialized to
undef.

In Python the most literal translation of the first code snippet
above triggers an IndexError exception:

>>> arr = list()
>>> arr[999] = 42

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range

In fact, one would need to pre-grow the list sufficiently to be
able to make an assignment like this one. I.e. one needs the
equivalent of the second Perl snippet above.

The best I can come up with is this:

arr = [None] * 1000000

Is this the most efficient way to achieve this result?

TIA!

kynn



kj
  Reply With Quote
Old 11-06-2009, 12:34 PM   #2
Paul Rubin
 
Posts: n/a
Default Re: Most efficient way to "pre-grow" a list?
kj <> writes:
> >>> arr[999] = 42

> ...
> The best I can come up with is this:
> arr = [None] * 1000000
> Is this the most efficient way to achieve this result?


If you're talking about an array of ints, use the array module.
You might also look at numpy.


Paul Rubin
  Reply With Quote
Old 11-06-2009, 02:11 PM   #3
Jon Clements
 
Posts: n/a
Default Re: Most efficient way to "pre-grow" a list?
On Nov 6, 12:12*pm, kj <no.em...@please.post> wrote:

[snip]

> In fact, one would need to pre-grow the list sufficiently to be
> able to make an assignment like this one. *I.e. one needs the
> equivalent of the second Perl snippet above.
>
> The best I can come up with is this:
>
> arr = [None] * 1000000
>
> Is this the most efficient way to achieve this result?


That's a good as it gets I think.

If sparsely populated I might be tempted to use a dict (or maybe
defaultdict):

d = {999: 42, 10673: 123}
for idx in xrange(1000000): # Treat it as though it's a list of
1,000,000 items...
print 'index %d has a value of %d' % (idx, d.get(idx, None))

Efficiency completely untested.

Jon.


Jon Clements
  Reply With Quote
Old 11-06-2009, 03:12 PM   #4
Andre Engels
 
Posts: n/a
Default Re: Most efficient way to "pre-grow" a list?
On Fri, Nov 6, 2009 at 1:12 PM, kj <> wrote:
>
> In Perl one can assign a value to any element of an array, even to
> ones corresponding to indices greater or equal than the length of
> the array:
>
> Â*my @arr;
> Â*$arr[999] = 42;
>
> perl grows the array as needed to accommodate this assignment. Â*In
> fact one common optimization in Perl is to "pre-grow" the array to
> its final size, rather than having perl grow it piecemeal as required
> by assignments like the one above:
>
> Â*my @arr;
> Â*$#arr = 999_999;
>
> After assigning to $#arr (the last index of @arr) as shown above,
> @arr has length 1,000,000, and all its elements are initialized to
> undef.
>
> In Python the most literal translation of the first code snippet
> above triggers an IndexError exception:
>
>>>> arr = list()
>>>> arr[999] = 42

> Traceback (most recent call last):
> Â*File "<stdin>", line 1, in <module>
> IndexError: list assignment index out of range
>
> In fact, one would need to pre-grow the list sufficiently to be
> able to make an assignment like this one. Â*I.e. one needs the
> equivalent of the second Perl snippet above.
>
> The best I can come up with is this:
>
> arr = [None] * 1000000
>
> Is this the most efficient way to achieve this result?


It depends - what do you want to do with it? My first hunch would be
to use a dictionary instead of a list, then the whole problem
disappears. If there is a reason you don't want to do that, what is
it?


--
André Engels,


Andre Engels
  Reply With Quote
Old 11-06-2009, 05:39 PM   #5
Raymond Hettinger
 
Posts: n/a
Default Re: Most efficient way to "pre-grow" a list?
[kj]
> In fact, one would need to pre-grow the list sufficiently to be
> able to make an assignment like this one. *I.e. one needs the
> equivalent of the second Perl snippet above.
>
> The best I can come up with is this:
>
> arr = [None] * 1000000
>
> Is this the most efficient way to achieve this result?


Yes.


Raymond



Raymond Hettinger
  Reply With Quote
Old 11-06-2009, 06:11 PM   #6
Emily Rodgers
 
Posts: n/a
Default Re: Most efficient way to "pre-grow" a list?

"Andre Engels" <> wrote in message
news:mailman.2696.1257520404.2807.python-...
>On Fri, Nov 6, 2009 at 1:12 PM, kj <> wrote:

[snip]
>> arr = [None] * 1000000
>>
>> Is this the most efficient way to achieve this result?

>
> It depends - what do you want to do with it? My first hunch would be
> to use a dictionary instead of a list, then the whole problem
> disappears. If there is a reason you don't want to do that, what is
> it?
>
> --
> André Engels,


I second this. It might seem a sensible thing to do in perl, but I can't
imagine what you would actually want to do it for! Seems like an odd thing
to want to do!




Emily Rodgers
  Reply With Quote
Old 11-06-2009, 09:03 PM   #7
kj
 
Posts: n/a
Default Re: Most efficient way to "pre-grow" a list?
In <hd1os1$aqs$> "Emily Rodgers" <> writes:


>"Andre Engels" <> wrote in message
>news:mailman.2696.1257520404.2807.python-...
>>On Fri, Nov 6, 2009 at 1:12 PM, kj <> wrote:

>[snip]
>>> arr = [None] * 1000000
>>>
>>> Is this the most efficient way to achieve this result?

>>
>> It depends - what do you want to do with it? My first hunch would be
>> to use a dictionary instead of a list, then the whole problem
>> disappears. If there is a reason you don't want to do that, what is
>> it?


>I second this. It might seem a sensible thing to do in perl, but I can't
>imagine what you would actually want to do it for! Seems like an odd thing
>to want to do!


As I said, this is considered an optimization, at least in Perl,
because it lets the interpreter allocate all the required memory
in one fell swoop, instead of having to reallocate it repeatedly
as the array grows. (Of course, like with all optimizations,
whether it's worth the bother is another question.)

Another situation where one may want to do this is if one needs to
initialize a non-sparse array in a non-sequential order, e.g. if
that's the way the data is initially received by the code. Of
course, there are many ways to skin such a cat; pre-allocating the
space and using direct list indexing is just one of them. I happen
to think it is a particularly straighforward one, but I realize that
others (you, Andre, etc.) may not agree.

kynn


kj
  Reply With Quote
Old 11-07-2009, 02:46 AM   #8
gil_johnson
 
Posts: n/a
Default Re: Most efficient way to "pre-grow" a list?
On Nov 6, 6:12*am, kj <no.em...@please.post> wrote:
> In Perl one can assign a value to any element of an array, even to
> ones corresponding to indices greater or equal than the length of
> the array:
>
> * my @arr;
> * $arr[999] = 42;
>
> perl grows the array as needed to accommodate this assignment. *In
> fact one common optimization in Perl is to "pre-grow" the array to
> its final size, rather than having perl grow it piecemeal as required
> by assignments like the one above:
>
> * my @arr;
> * $#arr = 999_999;
>
> After assigning to $#arr (the last index of @arr) as shown above,
> @arr has length 1,000,000, and all its elements are initialized to
> undef.
>
> In Python the most literal translation of the first code snippet
> above triggers an IndexError exception:
>
> >>> arr = list()
> >>> arr[999] = 42

>
> Traceback (most recent call last):
> * File "<stdin>", line 1, in <module>
> IndexError: list assignment index out of range
>
> In fact, one would need to pre-grow the list sufficiently to be
> able to make an assignment like this one. *I.e. one needs the
> equivalent of the second Perl snippet above.
>
> The best I can come up with is this:
>
> arr = [None] * 1000000
>
> Is this the most efficient way to achieve this result?
>
> TIA!
>
> kynn


I don't have the code with me, but for huge arrays, I have used
something like:

>>> arr[0] = initializer
>>> for i in range N:
>>> arr.extend(arr)


This doubles the array every time through the loop, and you can add
the powers of 2 to get the desired result.
Gil


gil_johnson
  Reply With Quote
Old 11-07-2009, 03:06 AM   #9
r
 
Posts: n/a
Default Re: Most efficient way to "pre-grow" a list?
On Nov 6, 6:12*am, kj <no.em...@please.post> wrote:
> In Perl one can assign a value to any element of an array, even to
> ones corresponding to indices greater or equal than the length of
> the array:
>
> * my @arr;
> * $arr[999] = 42;
>
> perl grows the array as needed to accommodate this assignment. *In
> fact one common optimization in Perl is to "pre-grow" the array to
> its final size, rather than having perl grow it piecemeal as required
> by assignments like the one above:
>
> * my @arr;
> * $#arr = 999_999;
>
> After assigning to $#arr (the last index of @arr) as shown above,
> @arr has length 1,000,000, and all its elements are initialized to
> undef.
>
> In Python the most literal translation of the first code snippet
> above triggers an IndexError exception:
>
> >>> arr = list()
> >>> arr[999] = 42

>
> Traceback (most recent call last):
> * File "<stdin>", line 1, in <module>
> IndexError: list assignment index out of range
>
> In fact, one would need to pre-grow the list sufficiently to be
> able to make an assignment like this one. *I.e. one needs the
> equivalent of the second Perl snippet above.
>
> The best I can come up with is this:
>
> arr = [None] * 1000000
>
> Is this the most efficient way to achieve this result?
>
> TIA!
>
> kynn


You mean sum'in like dis?

class PerlishList(list):
'''Hand holding list object for even the most demanding Perl
hacker'''
def __init__(self, dim=0):
list.__init__(self)
if dim:
self.__setitem__(dim, None)

def __setitem__(self, idx, v):
lenkeys = len(self)
sup = super(PerlishList, self)
if idx > lenkeys:
for idx in range(lenkeys, idx):
sup.append(None)
sup.__setitem__(idx, v)

def __getitem__(self, idx):
return self[idx]

l = PerlishList(3)
l.append('a')
l.append('b')
print l
l[10] = 10
print l




r
  Reply With Quote
Old 11-07-2009, 03:07 PM   #10
Steven D'Aprano
 
Posts: n/a
Default Re: Most efficient way to "pre-grow" a list?
On Fri, 06 Nov 2009 18:46:33 -0800, gil_johnson wrote:

> I don't have the code with me, but for huge arrays, I have used
> something like:
>
>>>> arr[0] = initializer
>>>> for i in range N:
>>>> arr.extend(arr)

>
> This doubles the array every time through the loop, and you can add the
> powers of 2 to get the desired result. Gil


Why is it better to grow the list piecemeal instead of just allocating a
list the size you want in one go?

arr = [x]*size_wanted



--
Steven


Steven D'Aprano
  Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
What is the most efficient way to generate monochromatic 5982 nmlight? GreenXenon Computer Support 4 02-13-2009 01:35 AM
Too efficient... dwacon. Computer Support 3 08-16-2005 06:54 PM
Domain Hosting Cost Efficient Nik Schlein Computer Support 8 05-26-2005 06:12 AM
Most cost efficient printer Pundit Computer Support 3 02-15-2005 12:47 AM
Although the Whirlpool Duet has better water efficiency, the Frigidaire Gallery is less expensive and cleans nearly as well, reviewers say. Experts like front-loaders Dobey House Elf Computer Security 3 07-21-2004 09:25 PM




SEO by vBSEO 3.3.2 ©2009, Crawlability, Inc.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46