Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Splitting an array into "even" parts

Reply
Thread Tools

Splitting an array into "even" parts

 
 
Tore Aursand
Guest
Posts: n/a
 
      11-05-2003
Hi there!

I need to split an array into "even" parts, so that each resulting array
contains the same number of elements.

Think of it as splitting a list of many names into multiple columns, and
you want x numbers of names in each column so that each column gets filled
up even-wise.

The problem arise, of course, when you have 10 elements and want to split
those into 3 columns. That should be listed like this:

+-------+-------+-------+
| Col 1 | Col 2 | Col 3 |
+-------+-------+-------+
| 1 | 5 | 9 |
| 2 | 6 | 10 |
| 3 | 7 | |
| 4 | 8 | |
+-------+-------+-------+

So far I've come up with this solution:

sub split_array {
my $array = shift; # Array reference
my $parts = shift; # Number of columns to split into

## Make sure $parts is set (default = 2), and that it isn't
## larger than the number of elements in $array
$parts ||= 2;
$parts = @$array if ( $parts > @$array );

## Split
my @split = (); # Will contain the splitted data
my $slice = POSIX::ceil( @$array / $parts ); # Size of each part

for ( 1 .. $parts ) {
if ( $_ == $parts ) {
push( @split, $array );
}
else {
push( @split, splice(@$array, 0, $slice) );
}
}

## Return
return \@split;
}

This code is doubtly the most efficient (I'm always looking for
efficient, yet readable, ways to do things), and I haven't run that many
tests on it either. Any comments on it?


--
Tore Aursand <(E-Mail Removed)>
 
Reply With Quote
 
 
 
 
Andreas Kahari
Guest
Posts: n/a
 
      11-05-2003
In article <(E-Mail Removed)>, Tore Aursand wrote:
> Hi there!
>
> I need to split an array into "even" parts, so that each resulting array
> contains the same number of elements.

[cut]
> This code is doubtly the most efficient (I'm always looking for
> efficient, yet readable, ways to do things), and I haven't run that many
> tests on it either. Any comments on it?


Here's something that doesn't rely on external modules:

sub split_array
{
my $arr = shift;
my $bins = shift;

my $size = int((scalar @{ $arr })/$bins);

if (scalar @{ $arr } % $bins != 0) {
++$size;
}

my @result;

for my $i (0 .. ($bins - 1)) {
push @result, [ @{ $arr }[$i*$size .. (($i + 1)*$size - 1)] ];
}

return @result;
}

--
Andreas Kähäri
 
Reply With Quote
 
 
 
 
Eric J. Roode
Guest
Posts: n/a
 
      11-05-2003
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Tore Aursand <(E-Mail Removed)> wrote in
news(E-Mail Removed):

> Hi there!
>
> I need to split an array into "even" parts, so that each resulting
> array contains the same number of elements.
>
> Think of it as splitting a list of many names into multiple columns,
> and you want x numbers of names in each column so that each column
> gets filled up even-wise.
>
> The problem arise, of course, when you have 10 elements and want to
> split those into 3 columns. That should be listed like this:
>
> +-------+-------+-------+
> | Col 1 | Col 2 | Col 3 |
> +-------+-------+-------+
> | 1 | 5 | 9 |
> | 2 | 6 | 10 |
> | 3 | 7 | |
> | 4 | 8 | |
> +-------+-------+-------+
>
> So far I've come up with this solution:
>
> sub split_array {
> my $array = shift; # Array reference
> my $parts = shift; # Number of columns to split into
>
> ## Make sure $parts is set (default = 2), and that it isn't
> ## larger than the number of elements in $array
> $parts ||= 2;
> $parts = @$array if ( $parts > @$array );
>
> ## Split
> my @split = (); # Will contain the splitted data
> my $slice = POSIX::ceil( @$array / $parts ); # Size of each part
>
> for ( 1 .. $parts ) {
> if ( $_ == $parts ) {
> push( @split, $array );
> }
> else {
> push( @split, splice(@$array, 0, $slice) );
> }
> }
>
> ## Return
> return \@split;
> }
>
> This code is doubtly the most efficient (I'm always looking for
> efficient, yet readable, ways to do things), and I haven't run that
> many tests on it either. Any comments on it?


aplice() pretty much does what you want by itself -- there's no need for
all the special-case-handling code you are surrounding it with.

sub split_array
{
my $array = shift;
my $parts = shift || 2;
my @array = @$array; # working copy
my @split; # result

while (@array)
{
push @split, [splice @array, 0, $parts];
}
return \@split;
}

or even:

push @split, [splice @array, 0, $parts] while @array;

- --
Eric
$_ = reverse sort $ /. r , qw p ekca lre uJ reh
ts p , map $ _. $ " , qw e p h tona e and print

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 7.0.3 for non-commercial use <http://www.pgp.com>

iQA/AwUBP6jsRmPeouIeTNHoEQJN/gCdG6n983iPY7jp14peWtV09TyG21AAnRH1
pu+8ZH/a6uRkk+sUbRLGbfx0
=fmD3
-----END PGP SIGNATURE-----
 
Reply With Quote
 
Tore Aursand
Guest
Posts: n/a
 
      11-05-2003
On Wed, 05 Nov 2003 06:25:41 -0600, Eric J. Roode wrote:
> sub split_array
> {
> my $array = shift;
> my $parts = shift || 2;
> my @array = @$array; # working copy
> my @split; # result
>
> while (@array)
> {
> push @split, [splice @array, 0, $parts];
> }
> return \@split;
> }


Fine solution, indeed, but still not satisfying me needs. Let's take a
look at an example:

my @array = ( 1..9 );
my $parts = 4;

Expected result should be:

[
[1,2,3],
[4,5],
[6,7],
[8,9]
]

But your function only returns 3 arrays. A note begins to form in my back
head: Make sure that @array is splittable in $parts parts.


--
Tore Aursand <(E-Mail Removed)>
 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      11-05-2003
Tore Aursand <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> On Wed, 05 Nov 2003 06:25:41 -0600, Eric J. Roode wrote:
> > sub split_array
> > {
> > my $array = shift;
> > my $parts = shift || 2;
> > my @array = @$array; # working copy
> > my @split; # result
> >
> > while (@array)
> > {
> > push @split, [splice @array, 0, $parts];
> > }
> > return \@split;
> > }

>
> Fine solution, indeed, but still not satisfying me needs. Let's take a
> look at an example:
>
> my @array = ( 1..9 );
> my $parts = 4;
>
> Expected result should be:
>
> [
> [1,2,3],
> [4,5],
> [6,7],
> [8,9]
> ]


Well, here's a variant that does that. It returns the array of split
parts directly, not a reference to it, but that's trivial to fix.

sub split_array {
my $parts = shift || 2;
my @array = @{ shift()};
my $size = int @array/$parts;
my $rem = @array % $parts;
map [splice @array, 0, $size + ($rem-- > 0)], 1 .. $parts;
}


Anno
 
Reply With Quote
 
Tore Aursand
Guest
Posts: n/a
 
      11-05-2003
On Wed, 05 Nov 2003 13:52:42 +0000, Anno Siegel wrote:
> sub split_array {
> my $parts = shift || 2;
> my @array = @{ shift()};
> my $size = int @array/$parts;
> my $rem = @array % $parts;
> map [splice @array, 0, $size + ($rem-- > 0)], 1 .. $parts;
> }


Most excellent. Seems to do excactly what I am looking for. Thanks a
lot, Anno!


--
Tore Aursand <(E-Mail Removed)>
 
Reply With Quote
 
 
 
Reply

Thread Tools

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

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


Similar Threads
Thread Thread Starter Forum Replies Last Post
Parts parts....PARTS!!! ARGHHH dstvns A+ Certification 8 01-07-2004 07:57 PM
(easy) splitting a file name into parts Andy Fish Java 4 08-24-2003 05:49 AM
Re: Splitting up the definitions of a class into different files (splitting public from private)? John Dibling C++ 0 07-19-2003 04:41 PM
Re: Splitting up the definitions of a class into different files (splitting public from private)? Mark C++ 0 07-19-2003 04:24 PM
Re: Splitting up the definitions of a class into different files (splitting public from private)? John Ericson C++ 0 07-19-2003 04:03 PM



Advertisments