How can I create a two-dimensional array in Perl?
Solution 1
It doesn't seem you understand that $matrix
only indicates @matrix
when it is immediately followed by an array indexer: [ $slot ]
. Otherwise, $matrix
is a completely different variable from @matrix
(and both different from %matrix
as well). See perldata.
#!/usr/bin/perl
use English;
Don't! use English--that way!
This brings in $MATCH
, $PREMATCH
, and $POSTMATCH
and incurs the dreaded $&
, $`, $'
penalty. You should wait until you're using an English variable and then just import that.
open FILE, "testset.txt" or die $!;
Two things: 1) use lexical file handles, and 2) use the three-argument open
.
my @lines = <FILE>;
As long as I'm picking: Don't slurp big files. (Not the case here, but it's a good warning.)
my $size = scalar @lines;
my @matrix = (1 .. 32);
my $i = 0;
my $j = 0;
my @micro;
I see we're at the "PROFIT!!" stage here...
foreach ($matrix) {
You don't have a variable $matrix
; you have a variable @matrix
.
foreach ($lines) {
The same thing is true with $lines
.
push @{ $micro[$matrix]}, $lines;
}
}
Rewrite:
use strict;
use warnings;
use English qw<$OS_ERROR>; # $!
open( my $input, '<', 'testset.txt' ) or die $OS_ERROR;
# I'm going to assume space-delimited, since you don't show
my @matrix;
# while ( defined( $_ = <$input> ))...
while ( <$input> ) {
chomp; # strip off the record separator
# Load each slot of @matrix with a reference to an array filled with
# the line split by spaces.
push @matrix, [ split ]; # split = split( ' ', $_ )
}
Solution 2
If you are going to be doing quite a bit of math, you might consider PDL (the Perl Data Language). You can easily set up your matrix and before operations on it:
use 5.010;
use PDL;
use PDL::Matrix;
my @rows;
while( <DATA> ) {
chomp;
my @row = split /\s+/;
push @rows, \@row;
}
my $a = PDL::Matrix->pdl( \@rows );
say "Start ", $a;
$a->index2d( 1, 2 ) .= 999;
say "(1,2) to 999 ", $a;
$a++;
say "Increment all ", $a;
__DATA__
1 2 3
4 5 6
7 8 9
2 3 4
The output shows the matrix evolution:
Start
[
[1 2 3]
[4 5 6]
[7 8 9]
[2 3 4]
]
(1,2) to 999
[
[ 1 2 3]
[ 4 5 999]
[ 7 8 9]
[ 2 3 4]
]
Increment all
[
[ 2 3 4]
[ 5 6 1000]
[ 8 9 10]
[ 3 4 5]
]
There's quite a bit of power to run arbitrary and complex operations on every member of the matrix just like I added 1 to every member. You completely skip the looping acrobatics.
Not only that, PDL does a lot of special stuff to make math really fast and to have a low memory footprint. Some of the stuff you want to do may already be implemented.
Solution 3
You probably need to chomp
the values:
chomp( my @lines = <FILE> );
Solution 4
To clarify a tangential point to Axeman's answer:
See perldoc -f split:
A split on
/\s+/
is like asplit(' ')
except that any leading whitespace produces a null first field. A split with no arguments really does asplit(' ', $_)
internally.
#!/usr/bin/perl
use YAML;
$_ = "\t1 2\n3\f4\r5\n";
print Dump { 'split' => [ split ] },
{ "split ' '" => [ split ' ' ] },
{ 'split /\s+/' => [ split /\s+/ ] }
;
Output:
--- split: - 1 - 2 - 3 - 4 - 5 --- split ' ': - 1 - 2 - 3 - 4 - 5 --- split /\s+/: - '' - 1 - 2 - 3 - 4 - 5
Solution 5
I see the question is pretty old, but as the author has just edited the question, perhaps this is still of interest. Also the link to the data is dead, but since other answers use space as the separator, I will too.
This answer demonstrates Tie::Array::CSV
which allows random access to a CSV (or other file parsable with Text::CSV
).
#!/usr/bin/env perl
use strict;
use warnings;
use Tie::Array::CSV;
## put DATA into temporary file
## if not using DATA, put file name in $file
use File::Temp ();
my $file = File::Temp->new();
print $file <DATA>;
##
tie my @data, 'Tie::Array::CSV', $file, {
text_csv => {
sep_char => " ",
},
};
print $data[1][2];
__DATA__
1 2 3 4 5
6 7 8 9 1
2 3 4 5 6
Alos
I work at Harvard Medical School as a bioinformatician, I also started a company called Blue Elephant Jewelers. I enjoy writing code in R, perl, c#, java, php, and python. I am handy with Oracle 10g, and mysql. I have a degree in Bioinformatics and worked as a windows systems administrator for over 10 years.
Updated on September 06, 2022Comments
-
Alos over 1 year
I am currently trying to pass a 32 by 48 matrix file to a multi-dimensional array in Perl. I am able to access all of the values, but I am having issues accessing a specific value.
Here is a link to the data set: http://paste-it.net/public/x1d5301/
Here is what I have for code right now.
#!/usr/bin/perl open FILE, "testset.txt" or die $!; my @lines = <FILE>; my $size = scalar @lines; my @matrix = (1 .. 32); my $i = 0; my $j = 0; my @micro; foreach ($matrix) { foreach ($lines) { push @{$micro[$matrix]}, $lines; } }
-
silbana over 13 years@Axeman FYI:
split
with no arguments issplit ' '
notsplit /\s+/
-
Axeman over 13 years@Sinan: Not on redhat Perl 5.8.7 or Strawberry Perl 5.12.1:perl -MSmart::Comments $_ = '1 2 3 4 5'; my @a = split; ### @a ### @a: [ ### '1', ### '2', ### '3', ### '4', ### '5' ### ]
-
Axeman over 13 years@Sinan, well HTML compressed the spaces, but there are all sorts of spaces and tabs in there. :/
-
ysth over 13 years@Axeman: can you explain what you mean? split with no arguments is definitely
split ' '
, notsplit /\s+/
. The two differ in how leading spaces are treated. -
silbana over 13 years@Axeman See the CW answer I added to illustrate the difference.
-
Axeman over 13 years@Sinan, @ysth, ah my reading of perlfunc is a little rusty. I had forgotten "As a special case, specifying a PATTERN of space (' ' ) will split on white space just as split with no arguments does". So I thought that the significance of
split( ' ' )
was it would only split on single-space characters--I only really use the shorthand of these functions in the toy code that I write on SO. You're right, @Sinan it does omit the initial zero-length string. My bad. And apparently that is simply to comply withawk
. -
Axeman over 13 years@Sinan: I guess my misguided point was that
split()
behaves more likesplit( /\s+/ )
than it doessplit( $char )
with$char = ' '
or$char = ','
. The' '
actually hides the full range of splitting behavior. -
silbana over 13 years@Axeman that's why I thought I should give you a heads up. Anyway, +1.