Looping through 2D array in Perl? - arrays

If I have a 2D array, how can it be possible to access an entire subarray inside of loop? Right now I have
foreach my $row(#data){
foreach my $ind(#$row){
#perform operations on specific index
}
}
but ideally I'm looking for something along the lines of
foreach my $row(#data){
#read row data like $row[0], which if it has the data I'm looking for
#I can go ahead and access $row[3] while in the same row..
}
I'm fairly new to Perl so might just not understand something yet, but I keep "Global symbol "#row" requires explicit package name" when trying to use it the way I want to.

You're close. $row is an array reference and you access its elements with the deference operator ->[...]:
foreach my $row (#data) {
if ($row->[0] == 42) { ... }
$row[0] refers to an element of the array variable #row, which is a completely different (and probably undefined -- thus the Global symbol ... error message) variable than $row.

If $row in your code sample is supposed to be a sub-array, or an array reference, you will have to use the indirect notation to access its elements, like $row->[0], $row->[1], etc.
The reason for your error is because $row[0] actually implies the existence of an array #row, which is probably not present in your script.

You could also try this...
my #ary = ( [12,13,14,15],
[57,58,59,60,61,101],
[67,68,69],
[77,78,79,80,81,301,302,303]);
for (my $f = 0 ; $f < #ary ; $f++) {
for (my $s = 0 ; $s < #{$ary[$f]} ; $s++ ) {
print "$f , $s , $ary[$f][$s]\n";
}
print "\n";
}

Related

How does foreach(#array, $var) work in Perl?

I am trying to figure out some Perl code someone else wrote, and I'm confused with the following syntax of foreach loop
foreach (#array, $var){
....
}
This code runs, but nobody else uses it based on my google search online. And it doesn't work the same way as the more common way of foreach with arrays, which is:
foreach $var (#array){
....
}
Could someone explain this syntax?
foreach (#array, $var){ .... }
is short for
foreach $_ (#array, $var){ .... }
which is short for
foreach $_ ($array[0], $array[1], ... $array[N], $var){ .... }
So on each iteration of the loop, $_ is set to be each element of the array and then finally to be $var. The $_ variable is just a normal perl variable, but one which is used in many places within the Perl syntax as a default variable to use if one is not explicitly mentioned.
Perl's for() doesn't operate on an array, it operates on a list.
for (#array, $var) {...}
...expands #array and $var into a single list of individual scalar elements, and then iterates over that list one element at a time.
It's no different than if you had of done:
my #array = (1, 2, 3);
my $var = 4;
push #array, $var;
for (#array) {...}
Also, for my $var (#array, $var) {...} will work just fine, because with my, you're localizing a new $var scalar, and the external, pre-defined one is left untouched. perl knows the difference.
You should always use strict;, and declare your variables with my.

perl: using push() on an array inside a hash

Is it possible to use Perl's push() function on an array inside a hash?
Below is what I believe to be the offending part of a larger program that I am working on.
my %domains = ();
open (TABLE, "placeholder.foo") || die "cannot read domtblout file\n";
while ($line = <TABLE>)
{
if (!($line =~ /^#/))
{
#split_line = split(/\t/, $line); # splits on tabs - some entries contain whitespace
if ($split_line[13] >= $domain_cutoff)
{
push($domains{$split_line[0]}[0], $split_line[19]); # adds "env from" coordinate to array
push($domains{$split_line[0]}[1], $split_line[20]); # adds "env to" coordinate to array
# %domains is a hash, but $domains{identifier}[0] and $domains{$identifier}[1] are both arrays
# this way, all domains from one sequence are stored with the same hash key, but can easily be processed iteratively
}
}
}
Later I try to interact with these arrays using
for ($i = 0, $i <= $domains{$identifier}[0], $i++)
{
$from = $domains{$identifier}[0][$i];
$to = $domains{$identifier}[1][$i];
$length = ($to - $from);
$tmp_seq =~ /.{$from}(.{$length})/;
print("$header"."$1");
}
but it appears as if the arrays I created are empty.
If $domains{$identifier}[0] is an array, then why can I not use the push statement to add an element to it?
$domains{identifier}[0] is not an array.
$domains{identifier}[0] is an array element, a scalar.
$domains{identifier}[0] is a reference to an array.
If it's
#array
when you have an array, it's
#{ ... }
when you have a reference to an array, so
push(#{ $domains{ $split_line[0] }[0] }, $split_line[19]);
References:
Mini-Tutorial: Dereferencing Syntax
References quick reference
perlref
perlreftut
perldsc
perllol

Beginner problems with perl

I have been tasked with correcting bugs in a chunk of Perl code and had a few questions about it (as I am new to Perl).
My first issue is what does the exclamation mark do?
if (!$superceded{returned->{$field}}) {
$found = 0;
foreach (blahblahblah)
My second problem is what does it mean if you have a variable $supercede and a hash %superceded and you write
(keys %$superceded)
Finally I have read up on these next two but I am still unsure on how they work. Setting a variable equal to shift and how to use "last;".
Thanks for any help and advice.
! is logical negation, which means if $cond is true, !$cond will be false. You could learn more about Truth and Falsehood from perlsyn.
If $hashref is a hash reference, then %$hashref is the hash that that reference referred to. For example,
my %hash = ( key1 => "val1", key2 => "val2" );
my $hashref = \%hash; # create a hash reference
while (my ($key, $val) = each %$hashref) {
# do something
}
Oh, you also could write something like this
my $hash = \%hash;
A little confusion to human readers, but Perl will accept it without any problem. To Perl, $hash and %hash are two completely different variables, and could be totally unrelated.
You could learn more about reference from perlref. And #$arrayref is similar, except in this case $arrayref is an array reference, it could be created by $arrayref = \#array;.
Setting a variable equal to shift
Do you mean something like this:
my $val = shift;
In this case, this means my $val = shift #_;, which will remove the first element of #_ and assign it to $val. See perldoc -f shift for further details.
how to use "last;"
If you want to finish a loop early, you could use last. For example,
foreach my $i (1..100) {
print "$i\n";
}
will print 1 to 100, and this
foreach my $i (1..100) {
print "$i\n";
last if $i == 5;
}
will only print 1 to 5. See perlsyn for further details.

2d arr explicitpackage

I've looked through several threads on websites including this one to try and understand why I am getting an undeclared variable error for my usage of my $line . Each element of the #lines array is an array of strings.
The error is in line 25 and 27 with the $line[$count] statement
use strict;
use warnings;
my #lines;
my #sizes;
# read input from stdin file into 2d array
while(<>)
{
push(#lines, my #tokens = split(/\s+/, $_));
}
# search through each array for largest sizes in
# corresponding elements
for (my $count = 0; $count <= 5; $count++)
{
push(#sizes, 0);
foreach my $line (#lines)
{
if(length($line[$count])>$sizes[$count])
{
$sizes[$count] = length($line[$count]);
}
}
}
I can post the full code if it is necessary, but I am pretty sure the error must be in here somewhere.
The problem is here:
push(#lines, my #tokens = split(/\s+/, $_));
Pushing one array into another just adds all elements to the first array. So you are making a really long one dimensional array.
To fix this, use brackets to make an array reference:
push #lines, [ split(/\s+/, $_) ]; #No need for a temp variable.
Also, to access the array reference, you have to de-reference it. Both of these syntaxes are options:
${$line}[$count];
$line->[$count];
I think the second syntax is more readable.
Update: Also, you could simplify your code if you keep track of the longest lengths while you go through the file:
use strict;
use warnings;
use List::Util qw/max/;
my #lines;
my #sizes = (0)x6;
while(<>)
{
push #lines, [ my #tokens = split ];
#sizes = map { max ( length($tokens[$_]), $sizes[$_] ) } 0..$#tokens;
}
Note: The Data::Dumper core module is an invaluable tool when working with complex data structures in Perl.
use Data::Dumper;
print Dumper #lines;
This will print out the complete structure of whatever variable you give it. That way you can see if you actually created what you thought you did.

How can I extract an array from a two-dimensional array in Perl?

I have once again forgotten how to get $_ to represent an array when it is in a loop of a two dimensional array.
foreach(#TWO_DIM_ARRAY){
my #ARRAY = $_;
}
That's the intention, but that doesn't work. What's the correct way to do this?
The line my #ARRAY = #$_; (instead of = $_;) is what you're looking for, but unless you explicitly want to make a copy of the referenced array, I would use #$_ directly.
Well, actually I wouldn't use $_ at all, especially since you're likely to want to iterate through #$_, and then you use implicit $_ in the inner loop too, and then you could have a mess figuring out which $_ is which, or if that's even legal. Which may have been why you were copying into #ARRAY in the first place.
Anyway, here's what I would do:
for my $array_ref (#TWO_DIM_ARRAY) {
# You can iterate through the array:
for my $element (#$array_ref) {
# do whatever to $element
}
# Or you can access the array directly using arrow notation:
$array_ref->[0] = 1;
}
for (#TWO_DIM_ARRAY) {
my #arr = #$_;
}
The $_ will be array references (not arrays), so you need to dereference it as:
my #ARRAY = #$_;

Resources