How can I iterate over a Perl array reference? - perl

I have an array that is a member of a structure:
$self->{myArray} = ["value1", "value2"];
And I'm trying to iterate over it using the following code:
my #myArray = $self->{myArray};
foreach my $foo (#myArray){
#Do something with the using $foo
...
}
The problem is that the 'foreach' loop is executed only once (when I would expect it to execute twice, since #myArray has two elements: "value1" and "value2").
When I check the #myArray array size, I get that its size is 1. What am I doing wrong in this code?

I believe that:
$self->{myArray} returns a reference.
You want to return the array:
#{$self->{myArray}}

$self->{myArray} is an array reference. You need to dereference it.
my #myArray = #{ $self->{myArray} };
In situations like this, the Data::Dumper module is very helpful. For example, if #myArray were not behaving as expected, you could run this code to reveal the problem.
use Data::Dumper;
print Dumper(\#myArray);

$self->{myArray} is an array reference, not an array - you can't store actual arrays inside a hash, only references. Try this:
my $myArray = $self->{myArray};
for my $foo (#$myArray){
# do something with $foo
}
You also may want to have a look at perldoc perlref.

Related

Perl: Calling a module method inside [ ]

Using an example, let a perl program start in the following fashion:
use strict;
use warnings;
use Time::HiRes;
What's the difference between
my $request_start_epoch = [Time::HiRes::gettimeofday];
and
my $request_start_epoch = Time::HiRes::gettimeofday;
?
The former calls the function in list context, assembles an anonymous array containing the elements of the returned list, and sets $request_start_epoch to a reference to that array.
The latter calls the function in scalar context and stores its return-value in $request_start_epoch.
These will almost always be different; the only time they would be the same is if the function's behavior in scalar context is to wrap up its list-context results in an anonymous array and return a reference to it. I've never seen any method written like that, but I'm sure someone somewhere has done it at some point!
The brackets [] convert what is returned by gettimeofday to an array reference. In your case, it would be a one element array.
Creating an array reference.
$arr_ref = [ 1,2,3,4,5 ];
Deferencing it.
#{ $arr_ref };
Accessing an element.
$ { $array_ref }[0]

How to manipulate a hash-ref with Perl?

Take a look at this code. After hours of trial and error. I finally got a solution. But have no idea why it works, and to be quite honest, Perl is throwing me for a loop here.
use Data::Diff 'Diff';
use Data::Dumper;
my $out = Diff(\#comparr,\#grabarr);
my #uniq_a;
#temp = ();
my $x = #$out{uniq_a};
foreach my $y (#$x) {
#temp = ();
foreach my $z (#$y) {
push(#temp, $z);
}
push(#uniq_a, [$temp[0], $temp[1], $temp[2], $temp[3]]);
}
Why is it that the only way I can access the elements of the $out array is to pass a hash key into a scalar which has been cast as an array using a for loop? my $x = #$out{uniq_a}; I'm totally confused. I'd really appreciate anyone who can explain what's going on here so I'll know for the future. Thanks in advance.
$out is a hash reference, and you use the dereferencing operator ->{...} to access members of the hash that it refers to, like
$out->{uniq_a}
What you have stumbled on is Perl's hash slice notation, where you use the # sigil in front of the name of a hash to conveniently extract a list of values from that hash. For example:
%foo = ( a => 123, b => 456, c => 789 );
$foo = { a => 123, b => 456, c => 789 };
print #foo{"b","c"}; # 456,789
print #$foo{"c","a"}; # 789,123
Using hash slice notation with a single element inside the braces, as you do, is not the typical usage and gives you the results you want by accident.
The Diff function returns a hash reference. You are accessing the element of this hash that has key uniq_a by extracting a one-element slice of the hash, instead of the correct $out->{uniq_a}. Your code should look like this
my $out = Diff(\#comparr, \#grabarr);
my #uniq_a;
my $uniq_a = $out->{uniq_a};
for my $list (#$uniq_a) {
my #temp = #$list;
push #uniq_a, [ #temp[0..3] ];
}
In the documentation for Data::Diff it states:
The value returned is always a hash reference and the hash will have
one or more of the following hash keys: type, same, diff, diff_a,
diff_b, uniq_a and uniq_b
So $out is a reference and you have to access the values through the mentioned keys.

How do I get a slice from an array reference?

Let us say that we have following array:
my #arr=('Jan','Feb','Mar','Apr');
my #arr2=#arr[0..2];
How can we do the same thing if we have array reference like below:
my $arr_ref=['Jan','Feb','Mar','Apr'];
my $arr_ref2; # How can we do something similar to #arr[0..2]; using $arr_ref ?
To get a slice starting with an array reference, replace the array name with a block containing the array reference. I've used whitespace to spread out the parts, but it's still the same thing:
my #slice = # array [1,3,2];
my #slice = # { $aref } [1,3,2];
If the reference inside the block is a simple scalar (so, not an array or hash element or a lot of code), you can leave off the braces:
my #slice = #$aref[1,3,2];
Then, if you want a reference from that, you can use the anonymous array constructor:
my $slice_ref = [ #$aref[1,3,2] ];
With the new post-dereference feature (experimental) in v5.20,
use v5.20;
use feature qw(postderef);
no warnings qw(experimental::postderef);
my #slice = $aref->#[1,3,2];
Just slice the reference (the syntax is similar to dereferencing it, see the comments), and then turn the resulting list back into a ref:
my $arr_ref2=[#$arr_ref[0..2]];
my $arr_ref2 = [ #$arr_ref[0..2] ];

How do I access the array's element stored in my hash in Perl?

# I have a hash
my %my_hash;
# I have an array
#my_array = ["aa" , "bbb"];
# I store the array in my hash
$my_hash{"Kunjan"} = #my_array;
# But I can't print my array's element
print $my_hash{"Kunjan"}[0];
I am new to Perl. Please help me.
Your array syntax is incorrect. You are creating an anonymous list reference, and #my_array is a single-element list containing that reference.
You can either work with the reference properly, as a scalar:
$my_array = ["aa" , "bbb"];
$my_hash{"Kunjan"} = $my_array;
Or you can work with the list as a list, creating the reference only when putting it into the hash:
#my_array = ("aa" , "bbb");
$my_hash{"Kunjan"} = \#my_array;
If you had only put this at the top of your script:
use strict;
use warnings;
...you would have gotten some error messages indicating what was wrong:
Global symbol "#my_array" requires explicit package name at kunjan-array.pl line 8.
Global symbol "#my_array" requires explicit package name at kunjan-array.pl line 11.
So, declare the array first with my #my_array; and then you would get:
Can't use string ("1") as an ARRAY ref while "strict refs" in use at kunjan-array.pl line 14.
You created an arrayref and attempted to assign it to an array - see perldoc perldata for how to declare an array
You attempted to assign an array to a hash (you can only assign scalars, such as an arrayref - see perldoc perlref for more about references)
You need to dereference the hash element to get at the array element, e.g. $my_hash{"Kunjan"}->[0] - again see perldoc perlref for how to dereference a hashref
You have a few errors in your program:
my #my_array = ("aa" , "bbb");
$my_hash{"Kunjan"} = \#my_array;
print $my_hash{"Kunjan"}[0];
I made three changes:
Added my in front of #my_array on the first line
Change the [...] to (...) on the first line
Add a \ in front of #my_array on the second line
Try these amendments:
my %my_hash;
# ["aa" , "bbb"] produces an array reference. Use () instead
my #my_array = ("aa" , "bbb");
# 'Kunjan' hash is given reference to #my_array
$my_hash{ Kunjan } = \#my_array;
# bareword for hash key is nicer on the eye IMHO
print $my_hash{ Kunjan }[0];
However there is still one thing you need to consider if you use this method:
unshift #my_array, 'AA';
print $my_hash{ Kunjan }[0]; # => AA - probably not what u wanted!
So what you are probably after is:
$my_hash{ Kunjan } = ["aa" , "bbb"];
Then the hash is no longer referencing #my_array.
/I3az/
Others already explained nicely what's what, but I would like to add, that (especially if you're new to Perl), it would be great if you spend some time and read the perldsc and perllol docs.

How can I create multidimensional arrays in Perl?

I am a bit new to Perl, but here is what I want to do:
my #array2d;
while(<FILE>){
push(#array2d[$i], $_);
}
It doesn't compile since #array2d[$i] is not an array but a scalar value.
How should I declare #array2d as an array of array?
Of course, I have no idea of how many rows I have.
To make an array of arrays, or more accurately an array of arrayrefs, try something like this:
my #array = ();
foreach my $i ( 0 .. 10 ) {
foreach my $j ( 0 .. 10 ) {
push #{ $array[$i] }, $j;
}
}
It pushes the value onto a dereferenced arrayref for you. You should be able to access an entry like this:
print $array[3][2];
Change your "push" line to this:
push(#{$array2d[$i]}, $_);
You are basically making $array2d[$i] an array by surrounding it by the #{}... You are then able to push elements onto this array of array references.
Have a look at perlref and perldsc to see how to make nested data structures, like arrays of arrays and hashes of hashes. Very useful stuff when you're doing Perl.
There's really no difference between what you wrote and this:
#{$array2d[$i]} = <FILE>;
I can only assume you're iterating through files.
To avoid keeping track of a counter, you could do this:
...
push #array2d, [ <FILE> ];
...
That says 1) create a reference to an empty array, 2) storing all lines in FILE, 3) push it onto #array2d.
Another simple way is to use a hash table and use the two array indices to make a hash key:
$two_dimensional_array{"$i $j"} = $val;
If you're just trying to store a file in an array you can also do this:
fopen(FILE,"<somefile.txt");
#array = <FILE>;
close (FILE);