Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Making little array babies

by Anonymous Monk
on Apr 12, 2004 at 04:27 UTC ( #344322=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'd like to split up an array into a bunch of smaller arrays each containing a specified amount of elements. Can't seem to figure out how to get it done.

Say I have an array of undetermined length (happens to be a bunch of image names read from a directory):
@images = ("IMAGE1","IMAGE2","IMAGE3","IMAGE4","IMAGE5","IMAGE6","IMAG +E7","IMAGE8","IMAGE9","IMAGE10", ect...);

and I want to break it up into smaller arrays of, let's say, three elements each:

@array1 = ("$images[0]","$images[1]","$images[2]"); @array2 = ("$images[3]","$images[4]","$images[5]"); @array3 = ("$images[6]","$images[7]","$images[8]"); @array4 = ("$images[9]");

How can I loop through this array while dynamically assigning a new array name every third time through the loop?

Any help is greatly appreciated.


Replies are listed 'Best First'.
Re: Making little array babies
by kvale (Monsignor) on Apr 12, 2004 at 04:53 UTC
    A simple way to do this is
    my @a = (1..16); my $kid_size = 3; my $num = int(@a/$kid_size); my @b; foreach my $i (0..$num-1) { $b[$i] = [splice @a,0,$kid_size]; } $b[$num] = [@a]; foreach my $i (0..$num) { print "b($i): ", join(",", @{$b[$i]}), "\n"; }
    Here I create an array of arrays $b[$i][$j] that is convenient for storing the babies.


Re: Making little array babies
by biosysadmin (Deacon) on Apr 12, 2004 at 04:54 UTC
    In order to make your program as general as possible, it's a good idea to use an array of arrays. This makes it possible to modify your program with minimal headaches. You can use the modulus operator to determine the array into which each image goes:
    my @images = qw( 1 .. 100 ); my @array_of_arrays; my $number_of_arrays = 2; my $count = 0; foreach my $image (@images) { my $index = $count % $number_of_arrays; push @{ $array_of_arrays[ $index ] }, $image; $x++; }
    Hope that this helps. Also, as a general hint be sure to use strict. :D
Re: Making little array babies
by davido (Cardinal) on Apr 12, 2004 at 04:58 UTC
    Here's one (untested) way...

    my @images = qw/IMAGE1 IMAGE2 IMAGE3 IMAGE4 IMAGE5 IMAGE6 IMAGE7 IMAGE8 IMAGE9 IMAGE10 IMAGE11/; my @lol; while ( @images ) { push @lol, [ map { (@images) ? shift @images : undef } 1..3 ]; }

    An artifact of this method is that if your initial array has a number of elements not evenly divisible by three you'll get one or two final elements that equate to undef in the last element in @lol.


      I personally like davido's solution the best, if you can live with the undef items at the end. However I would change the push, in the case where the baby arrays are small to :

      push @lol, [ shift(@images), shift(@images), shift(@images) ];

      It's just more explicit. The guy that comes after you won't have to think about what is going on here, it's obvious.

      Of course if the actual baby arrays are large, or thier length changes programatically, stick with his original code.

        Thank you all for the help,

        It was a good introduction to understanding how to store arrays in an array. I ended up using a combination of davido and nmcfarl's code which worked quite nicely and was understandable to look at quickly.

        Also, as I was halfway through reading the responses, I noticed someone named Randal L. Schwartz had replied, then a few minutes later I happen to glance down at the author of the book open in front of me... quite an honor.

•Re: Making little array babies
by merlyn (Sage) on Apr 12, 2004 at 11:25 UTC
    First, you really don't want named arrays like FOO1, FOO2, FOO3. You'll probably want those as arrayrefs in a master array. Presuming that, this'll do:
    my @copy = @images; my @result; push @result, [splice @copy, 0, 3] while @copy;

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: Making little array babies
by gjb (Vicar) on Apr 12, 2004 at 17:58 UTC

    And of course there's a module on CPAN to do this for you: Array::Dissect. It splits an array into arrays of given size.

    Hope this helps, -gjb-

Re: Making little array babies
by jdporter (Chancellor) on Apr 12, 2004 at 17:43 UTC
    I have a solution which I believe is better because it does not change the source array (@images), as do the other ideas suggested so far.
    my @a = qw( a b c d e f g ); my $n = 3; my @b; for ( my $i = 0; $i <= $#a; $i += $n ) { push @b, [ @a[ $i .. $i+$n-1 ] ]; }
    It's also really simple. :-)

    The 6th Rule of Perl Club is -- There is no Rule #6.

      To aid in my irrational goal to never use the C-style for loop in Perl -- as well as the more widely accepted goal of TMTOWTDI -- here's how I'd do that:

      my @a = qw(a b c d e f g); my $n = 3; my @b; for (0 .. $#a/$n) { push @b, [ @a[$_*$n .. $_*$n+$n-1] ]; }

      I was going to make the case that I like to avoid the C-style for loop because it looks ugly in Perl with all the sigils clogging things up, but after I typed out my alternative, I realized its readability is not much better. *shrug*

        Well, the direct equivalent* of mine, above, would be:
        (* other than scoping issues of $i)

        my $i = 0; while ( $i <= $#a ) { push @b, [ @a[ $i .. $i+$n-1 ] ]; } continue { $i += $n; }
        Thing I don't like about yours is the incessant multiplication by $n.

        The 6th Rule of Perl Club is -- There is no Rule #6.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://344322]
Approved by kvale
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (2)
As of 2023-03-25 10:36 GMT
Find Nodes?
    Voting Booth?
    Which type of climate do you prefer to live in?

    Results (63 votes). Check out past polls.