Split multidimensional array into 4 multidimensional arrays

Split multidimensional array into 4 multidimensional arrays

Post by kold » Fri, 17 Oct 2003 06:23:16


Hello everyone,

I have a multidimensional array that I need to split into 4
multidimensional arrays. I've tried the examples from the Programming
Perl 3rd ed. Chapter 9 for splicing Arrays of Arrays and am not having
any luck.

Here's an example of how my data looks:

[1 2 3 4 5 6 7 8 9 10 11 12]
[A B C D E F G H I J K L]

Here's how I need it to look:

[1 2 3 4] [5 6 7 8]
[A B C D] [E F G H]

[9 10] [11 12]
[I J] [K L]

The code I used

#!/usr/bin/perl

use warnings;
use strict;
use Data::Dumper;

my @AoA = ();
push @AoA, qw[1 2 3 4 5 6 7 8 9 10 11 12];
push @AoA, qw[A B C D E F G H I J K L];

print Dumper(\@AoA);

my @newAoA = ();
for (my $startx = my $x = 4; $x <= 8; $x++) {
for (my $starty = my $y = 7; $y <= 12; $y++) {
$newAoA[$x - $startx][$y - $starty] = $AoA[$x][$y];
}
}

print @newAoA;


The error I got is:

Can't use string ("5") as an ARRAY ref while "strict refs" in use at
./splice.pl line 16.


Any ideas?

Thanks in advance for any help!

--
Kevin Old < XXXX@XXXXX.COM >
 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by jame » Fri, 17 Oct 2003 06:43:21


Hmm, I'm a little lost at this point.


This isn't an array of arrays at this point. Just want to make sure
you know that. It's one long array with 1 - 12 at the front and A - L
at the back.

If you meant for this to be a multidimensional array, try:

my @AoA = ( [ 1..12 ], [ 'A'..'L' ] );


This would show that, if it was compiling.


Obviously this code doesn't work. It's a referencing issue. I would
try to correct it, but I don't understand the goal. Can you try taking
another stab at explaining how the array should look in the end?

James

 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by kold » Fri, 17 Oct 2003 10:22:42


Yes, you're right. This is how I meant to define my array:

my @AoA = ( [ 1..12 ], [ 'A'..'L' ] );

Ok, what I need is for the AoA to be reformatted like this into another
AoA.


1st 4 columns(1-4,A-D), "empty column", Next 4 columns(5-8,E-H)
"empty row in AoA"
Next 2 columns(9-10,I-J), "empty column", Last 2 columns(11-12,K-L)

Does this explain it?

Thanks for any help you can offer.


BTW, this code is straight from Programming Perl 3rd ed. Chapter 9.

Thanks for your help!

Kevin

--
Kevin Old < XXXX@XXXXX.COM >
 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by rob » Fri, 17 Oct 2003 16:55:22

evin Old wrote:

Hi Kevin.

The program below does what I think you mean. But you end up with
a three-dimensional array instead of the two-dimensional one you
started with. Is that right?

HTH,

Rob



use strict;
use warnings;

use Data::Dumper;

my @AoA = ( [ 1 .. 12 ], [ 'A'..'L' ] );

foreach (4, 4, undef, 2, 2) {

if ( defined ) {
push @AoA, [
[ splice @{$AoA[0]}, 0, $_ ],
undef,
[ splice @{$AoA[1]}, 0, $_ ],
];
}
else {
push @AoA, undef;
}
}

splice @AoA, 0, 2; # Remove the original two rows

print Data::Dumper->Dump( [\@AoA], ['*AoA'] );

** OUTPUT ** (reformatted)

@AoA = (
[
[ 1, 2, 3, 4 ],
undef,
[ 'A', 'B', 'C', 'D' ]
],
[
[ 5, 6, 7, 8 ],
undef,
[ 'E', 'F', 'G', 'H' ]
],
undef,
[
[ 9, 10 ],
undef,
[ 'I', 'J' ]
],
[
[ 11, 12 ],
undef,
[ 'K', 'L' ]
]
);


 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by kold » Fri, 17 Oct 2003 23:16:06

James,




Yes, this is what I'm trying to get for a result. I'm dumb too, that's
why I'm formatting data this way.

What needed to happen was that the data be broken down and displayed
into quadrants out of the two-dimensional array. I say needed because
the data feed I get has been reformatted so I don't have to worry about
that anymore.

I would however be interested in knowing how to get my previous array
into the @array_2d above.


I treasure it too. I wasn't doubting it's code, it was MY code I was
questioning.

Thanks for all you're help!
Kevin
--
Kevin Old < XXXX@XXXXX.COM >
 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by jame » Sat, 18 Oct 2003 00:52:13


That's a tricky question for me to answer. I can think of a lot of
ways to change it, but I'm not sure I understand the pattern you were
using. If I had divided 12 items equally into quadrants it would have
been three per quad. I might have done that like:

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

my @AoA = ( [ 1..12 ], [ 'A'..'L' ] );

print Dumper(\@AoA);

# figure out where to break them up
my $quad_count = @{$AoA[0]} / 4;
$quad_count++ if $quad_count =~ s/\.\d+$//; # round up

my @array_2d = ( [ ], [ ], [ ], [ ], [ ] );
# walk the old rows index by index moving them to the new array
# in the right spot
for my $old_row ( 0, 1 ) {
for my $index ( 0 .. $#{$AoA[0]} ) {
my $new_row = $index < 2 * $quad_count ? $old_row : $old_row + 3;
if ( $index < 2 * $quad_count ) {
$array_2d[ $new_row ][ $index ] = $AoA[ $old_row ][ $index ];
}
else {
$array_2d[ $new_row ][ $index - 2 * $quad_count ] =
$AoA[ $old_row ][ $index ];
}
}
}
# add undefs to break up the quads
splice @{ $array_2d[ $_ ] }, $quad_count, 0, undef foreach 0, 1, 3, 4;

print Dumper(\@array_2d);

__END__

However, not understanding your pattern, I probably would have written
the much uglier and nearly useless:

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

my @AoA = ( [ 1..12 ], [ 'A'..'L' ] );

print Dumper(\@AoA);

my @array_2d = ( [ ], [ ], [ ], [ ], [ ] );
push @{ $array_2d[0] }, @{ $AoA[0] }[ 0..3 ], undef, @{ $AoA[0] }[ 4..7
];
push @{ $array_2d[1] }, @{ $AoA[1] }[ 0..3 ], undef, @{ $AoA[1] }[ 4..7
];
push @{ $array_2d[3] }, @{ $AoA[0] }[ 8, 9 ], undef, @{ $AoA[0] }[ 10,
11 ];
push @{ $array_2d[4] }, @{ $AoA[1] }[ 8, 9 ], undef, @{ $AoA[1] }[ 10,
11 ];

print Dumper(\@array_2d);

__END__

Given that, I figured it was better just to show it in assignment form.

Maybe it you explain how you were dividing them up, I could do a little
better. Sorry if I'm still not helping much.

James
 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by pfeiffe » Sat, 18 Oct 2003 05:49:36

In article < XXXX@XXXXX.COM >, Kevin Old



Here's my version (I did need to peek at the Cookbook). I think this is what
you asked for...

my @AoA = (
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
['A'..'L'],
);

my (@AoA1, @AoA2, @AoA3, @AoA4);

for (0..$#AoA) {
# slice of AoA -- note position of {}s for AoA slice !!!!
push @AoA1, [ @{$AoA[$_]}[0..3] ];
push @AoA2, [ @{$AoA[$_]}[4..7] ];
push @AoA3, [ @{$AoA[$_]}[8..9] ];
push @AoA4, [ @{$AoA[$_]}[10..11] ];
}

# print Dumper(\@AoA1);

print "Array 1:\n";
foreach (@AoA1) {
print "@{$_}\n";
}

print "\n\n";

print "Array 2:\n";
foreach (@AoA2) {
print "@{$_}\n";
}

print "\n\n";

print "Array 3:\n";
foreach (@AoA3) {
print "@{$_}\n";
}

print "\n\n";


print "Array 4:\n";
foreach (@AoA4) {
print "@{$_}\n";
}

__END__

Output:

Array 1:
1 2 3 4
A B C D


Array 2:
5 6 7 8
E F G H


Array 3:
9 10
I J


Array 4:
11 12
K L


Am I close?



-K
--
Kevin Pfeiffer
International University Bremen
 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by kold » Sat, 18 Oct 2003 06:02:43

n Thu, 2003-10-16 at 11:52, James Edward Gray II wrote:

James, is it possible to ask for a little more help with this?

Here's the actual data I'm parsing (it's padded with spaces, but dont'
worry about them) and delimited by semicolon's.

DATE;WM REPL SHIPPED;STD REPL SHIPPED;PROMO SHIPPED;ROLLOUT
SHIPPED;OTHER SHIPPED;M/I SHIPPED;TOTAL SHIPPED;WM REPL OPEN;STD REPL
OPEN;PROMO OPEN;ROLLOUT OPEN;OTHER OPEN;M/I OPEN;TOTAL OPEN;LATE
ORDERS;DUMMY ORDERS;DELETED ORDERS;HELD ORDERS
; ; ; ; ;
; ; ; ; ;
; ; ; ; ;
; ; ;
20031002; 5764; 114978; 2288; ;
39; ; 123069; ; ;
; ; ; ; ;
; ; ;
20031003; 55523; 54923; 1105840; ;
157597; 3220; 1377103; ; ;
; ; ; ; ;
; ; ;
20031006; 64457; 152142; 771045; ;
46; 1319; 989009; ; ;
; ; ; ; ;
; ; ;
20031007; 17841; 49993; 190107; ;
28778; 6971; 293690; ; ;
; ; ; ; ;
; ; ;
20031008; 12347; 103861; 1323307; ;
; 9899; 1449414; ; ;
; ; ; ; ;
; ; ;
20031009; 95842; 165819; 977485; ;
3882; 9865; 1252893; ; ;
; ; ; ; ;
; ; ;
20031010; 14384; 131304; 756744; ;
18476; 2152; 923060; ; ;
; ; ; ; ;
; ; ;
20031011; 109672; 132782; 89539; ;
11900; 3834; 347727; ; ;
; ; ; ; ;
; ; ;
20031012; 53112; 118962; 86163; ;
; ; 258237; ; ;
; ; ; ; ;
; ; ;
20031013; 55604; 50646; ; ;
; ; 106250; ; ;
; ; ; ; ;
; ; ;
20031014; 88531; 102857; 529651; ;
; 5782; 726821; 582234; 863117;
9196512; ; 87790; 64738; 10794391;
3740624; 50400; ;


There are 19 columns and what I need is:

The first 8 column in quadrant 1
The next 7 columns in quadrant 2
The Date column (from Q1, 1st column) again, plus the next 7 columns a
 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by jame » Sat, 18 Oct 2003 06:53:07

n Thursday, October 16, 2003, at 03:25 PM, Kevin Old wrote:


Nope, you've used up all your free answer tokens. <laughs> Oh,
alright, just this once...


Ah, the Real-Question-Switcheroo! ;)


Okay, are these quadrants on going lists I should keep adding rows too?
I'm going to assume yes, for now.


Okay, first, just have to ask this question: Are we doing this in the
best way we possibly can? What about something like this?

my @data;
my @headers = split /;/, scalar <DATAFILE>;
while (<DATAFILE>) {
chomp;
my @fields = split /;/, $_;
foreach (@fields) { s/^\s+//; s/\s+$//; }
push @data, { map { ($header[$_], $fields[$_]) } 0..$#headers };
}

print Dumper(\@data); # so you can see what it makes...

Okay, enough with my tangent. I'll assume you know what you want and
we'll give that a go. Let's change it up a little though, to make my
life easier, which is all we really care about ;) :

my %quads = ( quad1 => [ ],
quad2 => [ ],
quad3 => [ ],
quad4 => [ ] );
while (<DATAFILE>) {
chomp;
my @fields = split /;/, $_;
foreach (@fields) { s/^\s+//; s/\s+$//; }
push @{ $quads{quad1} }, [ @fields[ 0..7 ] ];
push @{ $quads{quad2} }, [ @fields[ 8..14 ] ];
# I didn't understand the spec perfectly, so you probably need to fix
# the following push() where I mostly guessed
push @{ $quads{quad3} }, [ @fields[ 0, 8..14 ] ];
push @{ $quads{quad4} }, [ @fields[ 15..18 ] ];
}

print Dumper(\%quads); # just to show what we have here

# or we can keep going to get back to the array you asked for...

my @array_2d = @{ $quads{quad1} };
for (my $i = 0; $i < @array_2d; $i++) {
push @{ $array_2d[$i] }, undef, @{ $quads{quad2}[$i] };
}
push @array_2d, [ ];
push @array_2d,
map { [ @{ $quads{quad3}[$_] }, undef, @{ $quads{quad4}[$_] } ] }
0..$#{ $quads{quad3} };

print Dumper(\@array_2d); # I believe that gets us back to where you
wanted to go

Hopefully there's some wisdom buried in all that array mumbo jumbo that
will help you along, Good luck.

James

 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by kold » Sun, 19 Oct 2003 00:15:36

n Thu, 2003-10-16 at 17:53, James Edward Gray II wrote:

Help with my script AND Comedy! Folks, don't forget to tip your
waitress... <grin>


Yeah, sorry about that.....I've learned my lesson....from now on, the
data goes in the first post. :D


Not sure I got your point. The data didn't have the look I needed.


Yes, this is almost what I need, but instead of the headers being in the
first column, I need the in the first row.

Here's an example I put together to build the first quad.
open (DATAFILE, "mthsum") or die "Can't open file $!\n";

my @tmp = ();
my $i = 0;
while(<DATAFILE>) {
chomp;
my $j = 0;
my @fields = split /;/, $_;
foreach (@fields) { s/^\s+//; s/\s+$//; }
#push @tmp, [ @fields[0..7] ];
foreach ( @fields[ 0..7 ] ) { # any idea
$tmp[$j][$i] = $_; # if there's a better
$j++; # way to write this
} # maybe without the $i and $j
$i++; # or as a push ???
}

print "$tmp[2][0]\n"; # result is STD REPL SHIPPED



Yes, this part is perfect.

James, again I sincerely appreciate your help with this script and am
once again awed by the open source community and the lengths some will
go to help others, no matter how complex and confusing the situation is.

Thanks so very much!

Kevin

--
Kevin Old < XXXX@XXXXX.COM >

 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by jame » Sun, 19 Oct 2003 03:42:35

n Friday, October 17, 2003, at 10:15 AM, Kevin Old wrote:


Thank ya. I'll be here all week. :P


You're right, it didn't. That was just my way of giving some other
ideas of possibly useful ways to look at that kind of data. I was just
making sure you knew what you wanted, which you clearly do. I find
your quadrant divided array a little hard to follow, which doesn't
matter at all, but I was just making sure there wasn't an easier way.
Feel free to ignore me, it works fine for my mother.


Add a:

<DATAFILE>;

before the while loop to throw away the headers. I think that's what
you meant.


Egad, scratch what I said before because that's obviously not what you
meant! You like pain don't you man? <laughs>

Alright, let's plan this out a little. You have a piece of working
code above. Good start. By the way, don't sweat making two variables,
if it works, it works. You might call them $x and $y though, to make
it a little easier to follow.

Back to our plan. You ARE making the first quadrant correctly. Now if
we put that in the @{ $quads{quad1} } from my example, we're a fourth
of the way there right? We could rework the above loop to add them
there instead or if we're truly lazy we could add a:

@{ $quads{quad1} } = @tmp;

just after the loop, eh?

Now for the other three quads. Could you whip up loops for them too?
I suspect you could since it's pretty much the exact same thing. Then
if we load them into the appropriate arrays from my example too, my
"prefect" code below finishes up the problem, right? How's that?

Aside: Is this the perfect way to code it up? Probably not. If you
do it just as I said, you'll have to read the data four times, which
won't be super zippy. However it IS using what we know and it IS a
functional solution from a simple plan, right? Don't underestimate
that. Once you have a solution, you could work on combining the loops,
right? You give that version to management with a speech about "a four
times increase in efficiency" and "your Cyber Ninja coding skills" are
you're a bloody hero. What's not to like about that? It's a short
step from there to being a hit with the ladies, we hope, and then...
Oh, you get the idea. ;)

Now, if that sounds adventurous, skip this next chunk of code and have
at it Cyber Ninja! If instead you're thinking, "Is this guy ever going
to solve my freakin' problem or what?", read on...

my %quads = { quad1 => [ ],
quad2 => [ ],
quad3 => [ ],
quad4 => [ ] };
while (<DATAFILE>) {
chomp;
my @fields = split /;/, $_;
foreach (@fields) { s/^\s+//; s/\s+$//; }
my @quad1 = @fields[0..7];
my @quad2 = @fields[8..14]
my @quad3 = @fields[0, 8..14];
my @quad4 = @fields[15..18];
# I'm not ashamed of using many variables to save my sanity!
if (not @{ $quads{quad1} }) {
@{ $quads{quad1} } } = map { [ $_ ] } @quad1;
@{ $quads{quad2} } } = map { [ $_ ] } @quad2;
@{ $quads{quad3} } } = map { [ $_ ] } @quad3;
@{ $quads{quad4} } } = map { [ $_ ] } @quad4;
}
else {
push @$_, shift @quad1 foreach @{ $quads{quad1} } };
push @$_, shift @quad2 foreach @{ $quads{quad2} } };
push @$_, shift @quad3 foreach @{ $quads{quad3} } };
push @$_, shift @quad4 foreach @{ $quads{quad4} } };
}
# yes, the above can be simplified a lot, if it bothers you
# but that is left as an exercise to the reader
}


Damn, I ov
 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by pfeiffe » Sun, 19 Oct 2003 17:12:44

Hi James,

In article < XXXX@XXXXX.COM >, James

[...]

I _think_ you meant to use parens and not curly brackets:
my %quads = ( quad1 => [ ],
quad2 => [ ],
quad3 => [ ],
quad4 => [ ]
);



--
Kevin Pfeiffer
International University Bremen
 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by pfeiffe » Sun, 19 Oct 2003 22:37:24

In article < XXXX@XXXXX.COM >, James

[...]

[...]
[...]


This is my new version (with headers in first column for each).
Improvements/advice welcome...

my %array_ref;

while (<DATA>) {
next if /^#.*/;
chomp;
my @fields = split /\s*;\s*/, $_;

push @{$array_ref{1}}, [ @fields[0..7] ];
push @{$array_ref{2}}, [ @fields[8..14] ];
push @{$array_ref{3}}, [ @fields[0, 8..14] ];
push @{$array_ref{4}}, [ @fields[15..18] ];

}

# use Data::Dumper;
# print Dumper(\%array_ref);
# exit;

foreach my $nbr (sort keys %array_ref) {
print "Array $nbr\:\n";

# loops through ea. array
foreach (@{ $array_ref{$nbr} }) {

# prints formatted row
foreach my $col (@{$_}) {
printf "%16s|", $col;
}
print "\n";
}
}



-Kevin

--
Kevin Pfeiffer
International University Bremen
 
 
 

Split multidimensional array into 4 multidimensional arrays

Post by jame » Sun, 19 Oct 2003 23:56:00


You're very right. Good catch.

James