views:

332

answers:

3

Okay, I've been struggling with this all weekend, and I've gotten plenty of help but I'm still not getting it. Here is my code so far: what I want to do is build a few matrices from user input. Eventually I want to multiply them. Another story.

input is as follows

1 2 2 4
4 5 6 6

1 2 2 3
1 2 2 3

sub makeMatrix {
  my ($input) = @_;
  my @mat;
  while (<$input>) {
    if ($input eq ""){
     print "it's blank\n";
     return;
    }
    else{
     push @mat, [ split ];
    }
    return \@mat;
    }
}

my @a = ();
while($a = <>) {
    chomp $a;
    push @a,($a);
    }


@matrices;
push @mat, (makeMatrix(@a));

foreach $input (@matrices){
    print "input was $input\n";

}

Why doesn't this work? Why does it not create an array of matrices in @matrices? Is it the return statement in the subroutine? My goal is to have two matrices in the matrices array. Thanks for all your help.

+1  A: 

You seem to be a bit confused about the meaning of the <> operator.

The line

while (<$input>)

is wrong. This tells Perl to read from a filehandle $input. However, what you have passed into the subroutine is not a filehandle, it's a piece of text. You don't need the <> here. Also, you seem to have discarded most of the input to the subroutine. You call it like this:

makeMatrix(@a)

but then you only use the first value of @a in the routine. The routine should look like this:

use warnings;
use strict;

sub makeMatrix {
    my @inputs = @_;
    my @mat;
    for my $input (@inputs) {
        # print "$input\n"; # debugging code left here for artistic effect
        if ($input eq "") {
            print "it's blank\n";
        }
        else{
            push @mat, [ split /\s+/, $input ];
        }
    }
    return \@mat;
}

my @a;

while ($a = <>) {
    chomp $a;
    push @a, $a;
}


my $matrices = makeMatrix (@a);

for my $row (@$matrices){
    for my $column (@$row) {
        print "input was $column\n";
    }
}
Kinopiko
Note that `split ' '` is different than `split /\s+/`. Slurping the file is neither necessary nor desirable. Passing all of the lines as a flattened array when that array might be large is bad practice.
Sinan Ünür
+1  A: 

You pass makeMatrix an array of strings yet the function pretends that it is passed a file handle.

I do not know why you are jumping through so many hoops, but that is the big problem with your code.

Also, if a true filehandle were passed to makeMatrix, the line

while (<$input>) {
   if ($input eq ""){

would not do what you think it should do.

while (<$input>) {

would read the line into $_ at each iteration. So:

   if ($input eq ""){

will always be false because $input would be a filehandle (and therefore not equal to the empty string). Further, even if you had correctly written

   if ($_ eq ""){

the condition would be false upon encountering an empty line because you did not chomp off the line ending ($_ would not be empty).

All in all, a veritable mess of code where the reader can only try to guess at what it is that you are trying to do. Think about what you want to accomplish and explain it a little better.

http://learn.perl.org/ has great resources for learning Perl.

The code below is horribly obscure and I would not recommend it to be used in production, but trying to figure out what it does might teach you a lot:

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

while ( my $matrix = read_matrix() ) {
    print Dumper $matrix;
}

sub read_matrix {
    local $/ = "\n\n";
    return if eof DATA;
    return [ map { [ split ] } split /\n/, scalar <DATA> ];
}

__DATA__
1 2 2 4
4 5 6 6

1 2 2 3
1 2 2 3

Output:

$VAR1 = [
          [
            '1',
            '2',
            '2',
            '4'
          ],
          [
            '4',
            '5',
            '6',
            '6'
          ]
        ];
$VAR1 = [
          [
            '1',
            '2',
            '2',
            '3'
          ],
          [
            '1',
            '2',
            '2',
            '3'
          ]
        ];
Sinan Ünür
@Kinopiko: he says that. What do you think needs clarification?
ysth
It says "$input is a filehandle" in the middle of the answer.
Kinopiko
+1  A: 

Matt, Please check what I have written below to see if I have understood the problem:

My general points are:

(1) Your example data does not quite work for matrix multiplication. If your first array is 2x4 then your second array must be 4x2 and your answer will be 2x2.

(2) Perl provides you with a very powerful data language (PDL) that is efficient at matrix manipulation. I suggest you use it if you are going to do a lot of matrix algebra.

(3) Per the solution below the matrix product drops out in 3 lines provided you have read your data into a 2D array ( AoA is array of arrays) first.

#!/usr/bin/perl
use strict;
use warnings;
use PDL; # perl data language enables matrix multiplication
use Inline::Files; #multiple virtual files inside code

my @AoA_A = make_matrix("ARRAY_A"); #read in 2D array
my @AoA_B = make_matrix("ARRAY_B");

my $a = pdl [ @AoA_A ]; #Construct new pdl object
my $b = pdl [ @AoA_B ];
my $c = $a x $b;  # x overload
print "matrix a", $a;
print "matrix b", $b;
print "matrix c",$c;

sub make_matrix {
    my $source = shift;
    my @AoA;
    while (<$source>){
        my @tmp = split;
        push @AoA, [ @tmp ];
    }
    return @AoA;  
}

__ARRAY_A__
1 2 2 4
4 5 6 6
__ARRAY_B__
1 2
2 3
1 2
2 3

It created the following output:

matrix a
[
 [1 2 2 4]
 [4 5 6 6]
]
matrix b
[
 [1 2]
 [2 3]
 [1 2]
 [2 3]
]
matrix c
[
 [15 24]
 [32 53]
]
heferav
Text corrected to reflect Sinan's comment.
heferav