http://www.perlmonks.org?node_id=324960

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

Hello everyone, I have:
@one = qw(A B C D); @two = qw(E F G H);

I want to build a multidimensional array from the above arrays. I want to put @one in the first "column" of the array. I want to put @two in the second "column" of the array.
I want the resulting MDA to look like:
@mda = ( [A][E], [B][F], [C][G], [D][H] );

Any ideas? Sorry if this is not clear.
Kevin

Replies are listed 'Best First'.
Re: build multidimensional array from arrays
by broquaint (Abbot) on Jan 29, 2004 at 17:00 UTC
    A simple map should do it
    use Data::Dumper; my @one = 'A' .. 'D'; my @two = 'E' .. 'H'; my @both = map [ $one[$_], $two[$_] ], 0 .. $#one; print Dumper \@both; __output__ $VAR1 = [ [ 'A', 'E' ], [ 'B', 'F' ], [ 'C', 'G' ], [ 'D', 'H' ] ];
    HTH

    _________
    broquaint

Re: build multidimensional array from arrays
by jonadab (Parson) on Jan 29, 2004 at 17:00 UTC

    Assuming @one and @two have the same number of elements and that you wanted each element to be an arrayref...

    @mda = map { [[$one[$_-1]], [$two[$_-1]]] } 1..@one;

    Or maybe more likely you simply wanted this...

    @mda = map { [$one[$_-1], $two[$_-1]] } 1..@one;

    It would also be possible to create a tied array that looks up its values in the other arrays in real time, but that would be more complicated and probably has no advantage, unless you want changes to the original arrays to be reflected in the multidimensional one.

    update: fixed subscripting fencepost error pointed out to me by revdiablo and L~R. And yes, if the arrays might not be the same length you can check which one is longer and use either the shorter or the longer one to determine the upper bound of the range operator, depending on which results you want (whether you want the arrayrefs that would have an undef element or not). But I got the impression from the question that they would necessarily be the same length.

    Since nobody else has done so, I will also point out that the syntax the OP used for the desired structure is wrong. He has this (which of course is a syntax error):

    @mda = ( [A][E], [B][F], [C][G], [D][H] );

    It appears that what he wanted is this:

    @mda = ( [A,E], [B,F], [C,G], [D,H], );

    Though I personally would have used the funny comma (=>) within each of those arrayrefs especially if there are exactly two elements in each. But that doesn't technically matter, I think.


    $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/
Re: build multidimensional array from arrays (mapcar)
by tye (Sage) on Jan 29, 2004 at 19:56 UTC

    You can also use mapcar (such as from Algorithm::Loops) to avoid indexing:

    use Algorithm::Loops qw( MapCarE ); my @one = qw( A B C D ); my @two = qw( E F G H ); my @tre = qw( W X Y Z );
    my @mda = MapCarE { [@_] } \( @one, @two, @tre );
    require Data::Dumper; print Data::Dumper->new([\@mda],['@mda']) ->Indent(1)->Terse(1)->Dump();
    produces
    [ [ 'A', 'E', 'W' ], [ 'B', 'F', 'X' ], [ 'C', 'G', 'Y' ], [ 'D', 'H', 'Z' ] ]

    - tye        

Re: build multidimensional array from arrays
by Limbic~Region (Chancellor) on Jan 29, 2004 at 17:04 UTC
    kevsurf,
    I misunderstood you in the CB:
    #!/usr/bin/perl -w use strict; my @one = qw(A B C D); my @two = qw(E F G H); my @mda; my $total = @one > @two ? $#one : $#two; push @mda , [ $one[$_] , $two[$_] ] for 0 .. $total;
    Cheers - L~R
Re: build multidimensional array from arrays
by blue_cowdawg (Monsignor) on Jan 29, 2004 at 17:05 UTC

    kevsurf check out the following code:

    use Data::Dumper; @one = qw(A B C D); @two = qw(E F G H); @mda=( [@one],[@two]); print Dumper(\@mda);

    When run yields:

    $VAR1 = [ [ 'A', 'B', 'C', 'D' ], [ 'E', 'F', 'G', 'H' ] ];

    Was that what you were after?


    Peter L. Berghold -- Unix Professional
    Peter at Berghold dot Net
       Dog trainer, dog agility exhibitor, brewer of fine Belgian style ales. Happiness is a warm, tired, contented dog curled up at your side and a good Belgian ale in your chalice.
      Well, no that wasn't what I was looking for, but it's a nice piece of code to add to my arsenal. That basically puts the contents of @one in the first *row* of the @mda, @two in the second *row*. I want it to go in @mda in the *columns*. So...
      $mda[0][0] = A; $mda[0][1] = B; so forth... $mda[1][0] = E; $mda[1][1] = F; so forth...

      A little background on why I want to do this is that I'm formatting data in arrays to that I can send the Spreadsheet::WriteExcel module a reference to an MDA so that it writes the spreadsheet "contents" from one call to
      $ws->write(0, 0, \@mda); #writes all data into spreadsheet

      Thanks,
      Kevin

        In that case, it's even easier:

        my @mda = ( [ @one ], [ @two ] );

        Update: Or, of course, to save a bit of typing:

        my @mda = \( @one, @two );

        dave