The benefits of pre-assignment seem to be marginal at best.

However, the method by which you assign your values to the array is considerable more important. Unfortunately, the best method is not a simple choice either. If you are filling an array with essentially static data, then assignment to an array slice seems to be optimal, but if you need to generate your data in a loop, building a list prior to slice assignment suddenly becomes your worst option. In this case, indexed assignment in a for loop wins hands down with push beating slice assignment (pre-allocated or no) into last place. This appears to be consistant for a wide range of array size from 100, to 100_000 elements. The results below for a arrays of 10_000 elements seem typical.

Of course, this is only part of the story. If your source of data for the array is a very fast process as typified my use of rand below and your arrays large or the re-filling frequent, then the differences could be significant. On the other hand, if the source of the data was an expensive process (RDMS query or similar), then the cost of the assignment becomes insignificant relative to that process and the assignment method should be chosen as that which most closely fits the way in which you aquire the data to put in the array.

If you are receiving the data en-bloc as a list or array then using a slice assignment will probably be a win. If you are getting the values 1 at a time, then indexed assignment is probably best though some algorithms, such as where you don't know how much data you are going to receive, then the simplicity and scalability of push is the natural choice.

One final thing regarding your sample code. You show the array being declared and filled within a subroutine but you don't indicate how you are intending to return this to the calling code. If efficiency is in anyway important, ensuring that you return a reference to the array and not return the array as a list will probably save you more time than any difference you might achieve through pre-allocation or assignment method combined.

Update: Bah! Humbug. Don't

#! perl -sw use vars '$size $cpu'; use strict; use Benchmark 'cmpthese'; $::size ||= 1000; $::cpu ||= 1; my @empty; my @prealloc; $#prealloc = $::size; cmpthese( -$::cpu, { push => 'push @empty, q{data} for 0 .. $::s +ize-1', assign => '$empty[$_] = q{data} for 0 .. $::s +ize-1', assignpre => '$prealloc[$_] = q{data} for 0 .. $::s +ize-1', slice => '@empty[0 .. $::size-1] = (q{data} x $::size)', slicepre => '@prealloc[0 .. $::size-1] = (q{data} x $::size)', }); cmpthese( -1, { push => 'push @empty, rand $::size for +0 .. $::size-1', assign => '$empty[$_] = rand $::size for +0 .. $::size-1', assignpre => '$prealloc[$_] = rand $::size for +0 .. $::size-1', slice => '@empty[0 .. $::size-1] = (map{rand $::size}1 .. + $::size)', slicepre => '@prealloc[0 .. $::size-1] = (map{rand $::size}1..$ +::size)', }); __END__ C:\test>arraybench -size=10000 -cpu=1 Benchmark: running assign, assignpre, push, slice, slicepre, each for +at least 1 CPU seconds... assign: 2 wallclock secs ( 1.01 usr + 0.00 sys = 1.01 CPU) @ 18 +.77/s (n=19) assignpre: 1 wallclock secs ( 1.01 usr + 0.00 sys = 1.01 CPU) @ 18 +.77/s (n=19) push: 1 wallclock secs ( 1.05 usr + 0.05 sys = 1.10 CPU) @ 13 +.61/s (n=15) slice: 2 wallclock secs ( 1.10 usr + 0.00 sys = 1.10 CPU) @ 26 +.32/s (n=29) slicepre: 1 wallclock secs ( 1.15 usr + 0.00 sys = 1.15 CPU) @ 26 +.04/s (n=30) Rate push assign assignpre slicepre slice push 13.6/s -- -28% -28% -48% -48% assign 18.8/s 38% -- -0% -28% -29% assignpre 18.8/s 38% 0% -- -28% -29% slicepre 26.0/s 91% 39% 39% -- -1% slice 26.3/s 93% 40% 40% 1% -- Benchmark: running assign, assignpre, push, slice, slicepre, each for +at least 1 CPU seconds... assign: 1 wallclock secs ( 1.06 usr + 0.00 sys = 1.06 CPU) @ 20 +.74/s (n=22) assignpre: 1 wallclock secs ( 1.15 usr + 0.00 sys = 1.15 CPU) @ 20 +.85/s (n=24) push: 1 wallclock secs ( 0.98 usr + 0.03 sys = 1.01 CPU) @ 15 +.83/s (n=16) slice: 1 wallclock secs ( 1.00 usr + 0.00 sys = 1.00 CPU) @ 6 +.99/s (n=7) slicepre: 1 wallclock secs ( 1.13 usr + 0.00 sys = 1.13 CPU) @ 7 +.07/s (n=8) Rate slice slicepre push assign assignpre slice 6.99/s -- -1% -56% -66% -66% slicepre 7.07/s 1% -- -55% -66% -66% push 15.8/s 127% 124% -- -24% -24% assign 20.7/s 197% 193% 31% -- -1% assignpre 20.9/s 198% 195% 32% 1% -- C:\test>

Update: See Abigail-II's following post for the real gen on pre-allocation and assignment method.

My benchmark was garbage it seems.


Nah! Your thinking of Simon Templar, originally played by Roger Moore and later by Ian Ogilvy

In reply to Re: array pre-allocation trick by BrowserUk
in thread array pre-allocation trick by Anonymous Monk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.