Let's make that code you have a little more Perl-y, and we'll do everything you need done in one pass:
my @a = ();
while(<>) {
push @a, [ split ];
}
This is taking a lot out of your answer, so I'll opt to explain it, rather than aiming for John Wayne-like answering reflexes. We'll start with your line here:
while(defined(my $a = <STDIN>))
Perl users know that many loops will implicitly use the $_
variable. If you need lots of nested loops, you should avoid using that variable, and use well-named variables for each level of looping, but in this case we only have one level, so let's go ahead and use it:
while(defined($_ = <STDIN>))
Now, Perl is kind enough to understand that we want to test for defined()
ness a lot, so it will allow us to shorten that to this:
while(<STDIN>)
This is implicitly translated by Perl as assigning the line read to $_
and returning true as long as the result is defined (and therefore until end-of-file occurs). However, Perl gives us one more trick:
while(<>)
This will loop over STDIN
or, if arguments are given on the command line, it will open those as files and loop over them. So this still reads from STDIN
:
./myscript.pl
But we can also read from one or more files:
./myscript.pl myfile [myfile2 [myfile3 ...]]
It's easier and more intuitive than using the shell to do the same (though this will still work):
cat myfile [myfile2 [myfile3 ...]] | ./myscript.pl
If you don't want this behavior, you can change it back to <STDIN>
, but consider keeping it.
The loop is:
push @a, [ split ];
First, split()
with no arguments is identical to split /\s+/, $_
(i.e. it splits the $_
string on occurrences of whitespace characters), and due to the subtleties of split
empty trailing fields are removed, so a chomp()
is unnecessary. Then, []
creates an anonymous array reference (which, in this case, contains the contents of our split $_
string). Then, we push that array reference onto @a
. Simple as pie, you now have a two-dimensional matrix from your standard input.