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

Hi, I've got a number of attributes to store for each user, so I want a matrix to hold this rather than x parallel arrays. I'm trying just to simulate a simple matrix as follows
#! /usr/bin/perl $a = 1; $b = 2; $c = 3; $d = 4; $e = 5; $f = 6; $g = 7; $h = 8; $i = 9; @row = (); @matrix=(); push (@row, $a); push (@row, $b); push (@row, $c); print "@row\n"; push(@{$matrix}, \@row); @row = (); push (@row, $d); push (@row, $e); push (@row, $f); print "@row\n"; push(@{$matrix}, \@row); @row = (); push (@row, $g); push (@row, $h); push (@row, $i); print "@row\n"; push(@{$matrix}, \@row); print "$$matrix[0][0] \n";
You get the idea... why am I getting 7 at the end instead of 1. I mean, I must be over-writing each line or something, but I don't know what!

Replies are listed 'Best First'.
Re: simple matrix
by ikegami (Patriarch) on May 04, 2006 at 03:06 UTC

    Is matrix a reference to an array (@{$matrix}) or an array (@matrix). You've used both. use strict is your friend. It would have caught that error.

    Also, you're always pushing a reference to the same variable (@row) over and over again. All rows of your matrix are going to be the same. The following creates multiple row variables (all named @row). The alternative would be to copy @row into a newly create anon aray by replacing \@row with [ @row ].

    #! /usr/bin/perl use strict; use warnings; use Data::Dumper; my $a = 1; my $b = 2; my $c = 3; # It's bad to use $a and $b my $d = 4; my $e = 5; my $f = 6; my $g = 7; my $h = 8; my $i = 9; my @matrix; { my @row; push(@row, $a); push(@row, $b); push(@row, $c); print "@row\n"; push(@matrix, \@row); } { my @row; push(@row, $d); push(@row, $e); push(@row, $f); print "@row\n"; push(@matrix, \@row); } { my @row; push(@row, $g); push(@row, $h); push(@row, $i); print "@row\n"; push(@matrix, \@row); } print(Dumper(\@matrix));

    or

    my @matrix = ( [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], );
Re: simple matrix
by GrandFather (Saint) on May 04, 2006 at 03:13 UTC

    You would be much better using a hash:

    use strict; use warnings; use Data::Dump::Streamer; my %users; while (<DATA>) { chomp; my ($user, @attributes) = split /\s*,\s*/; $users{$user} = [@attributes]; } print $_, " @{$users{$_}}\n" for keys %users; __DATA__ Fred, 17, male, Perl monk Joe, 23, male, Perl Monk Jane, 22, female, Java junkie

    Prints:

    Jane 22 female Java junkie Joe 23 male Perl Monk Fred 17 male Perl monk

    DWIM is Perl's answer to Gödel
Re: simple matrix
by Samy_rio (Vicar) on May 04, 2006 at 04:10 UTC

    Hi steverippl, Try this another way,

    TIMTOWDI

    use strict; use warnings; use Array::Reform; my $a = 1; my $b = 2; my $c = 3; my $d = 4; my $e = 5; my $f = 6; my $g = 7; my $h = 8; my $i = 9; my @matrix; push(@matrix, $a); push(@matrix, $b); push(@matrix, $c); push(@matrix, $d); push(@matrix, $e); push(@matrix, $f); push(@matrix, $g); push(@matrix, $h); push(@matrix, $i); my $rowsize = 3; ####Number of rows for my $row (Array::Reform->reform( $rowsize, \@matrix )){ $,=" "; print @{$row}, "\n"; } __END__ 1 2 3 4 5 6 7 8 9

    GrandFather done well.

    Updated: instead of pushing value into an array in line by line. Use looping,

    push(@matrix, $_) foreach($a, $b, $c, $d, $e, $f, $g, $h, $i);

    Regards,
    Velusamy R.


    eval"print uc\"\\c$_\""for split'','j)@,/6%@0%2,`e@3!-9v2)/@|6%,53!-9@2~j';

Re: simple matrix
by jdtoronto (Prior) on May 04, 2006 at 03:29 UTC
    And you would be well advised to spend some time becoming acquainted with the "Perl Data Structures Cookbook", found in your documentation as "perldsc".

    You might also be well advised to consider using an HoH - a Hash of Hashes which means you do not need to fill every position in the matrix. Whilst in other languages you might find a matrix the easiest way of dealing with such a dataset it has been my experience that in Perl it is rarely the best way. Matrices are best kept for dealing with data which can be represented no other way.

    I would also re-iterate the advice already given that you should always use strict and warnings, you would have found the error long before opening your browser to come here.

    jdtoronto

Re: simple matrix
by davidrw (Prior) on May 04, 2006 at 13:20 UTC
    gotta add the caveat about $a and $b -- i know this is example code, but don't use those variable names .. they are special global variables for sort

    Can't tell if you really need hardcoded values or if you just flattened it for an example, but if the former you can just do (this should also help visualize the data structure):
    use strict; use warnings; my @matrix = ( [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], ); use Data::Dumper; print Dumper \@matrix; print $matrix[1]->[2] . "\n"; # prints "6"
Re: simple matrix
by steverippl (Novice) on May 04, 2006 at 15:28 UTC
    Thanks to all of you. Appologies for the sloppy coding, I thought I was saving time in trying to do this little test, but obviously that doesn't pay!! I needed to keep using @row to add to the array because this will happen in a loop, so as long as variables are local and I contain it in {} it works - great! The hash of arrays is probably my best bet as all users have unique usrName.

      Here's an updated solution given the new context.

      Doesn't work:

      for (...) { @row = (); ... push(@maxtrix, \@row); }

      Works:

      for (...) { my @row; ... push(@maxtrix, \@row); }

      In the first, each row of the matrix is a reference to the same array (@main::row).
      In the second, a new lexical is created every time through the loop, so each row of the matrix is a reference to a different array.

      For example,