perl send internal array as argument to subroutine - perl

I have a 2 dimensional array like this:
$map[0][0] = 'a';
$map[0][1] = 'b';
$map[1][0] = 'c';
$map[1][1] = 'd';
I want to pass only everything under $map[1] (by reference) to a subroutine. How to do that ?

Perl doesn't have multiple dimension arrays.
What you have is an array and each element of that array is a reference to another array. You might want to read up about Perl References since this is the way Perl allows you to build some very complex data structures.
Many people think of it as a multidimensional array, and you could treat it as such under certain circumstances. However, I prefer the -> syntax which reminds me that this is merely a reference to a reference.
$map[0]->[0] = 'a';
$map[0]->[1] = 'b';
$map[1]->[0] = 'c';
$map[1]->[1] = 'd';
Now, I can take the data structure apart:
#map: This is an array with two items in it, $map[0] and $map[1].
$map[0]->[]: This is a reference to another array. That array also has to items in it.
$map[1]->[]: This is another reference to yet another array. That array has two items in it.
Note that $map[1]->[] means that $map[1] contains an array reference. Thqt means you can pass $map[1] as your reference to that inner array.
mysub ($map[1]);
Here's a simple program:
#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);
my #map;
$map[0]->[0] = 'a';
$map[0]->[1] = 'b';
$map[1]->[0] = 'c';
$map[1]->[1] = 'd';
mysub( $map[1] );
sub mysub {
my $array_ref = shift;
my #array = #{ $array_ref }; # Dereference your reference
for my $index ( 0..$#array ) {
say "\$map[1]->[$index] = $array[$index]";
}
}
This prints:
$map[1]->[0] = c
$map[1]->[1] = d
Now, you see why I like that -> syntax although it's really completely unnecessary. It helps remind me what I am dealing with.

You can send array reference,
sub mysub {
my ($aref) = #_;
# work with #$aref ..
}
mysub($map[1]);

Simply pass the scalar $map[1].
fn($map[1]);
sub fn
{
my #loc_map_1 = #{ $_[0] };
Remember that perl doesn't have "real" 2 dimensional arrays. In your case map is an array that contains 2 references to arrays.

Related

What's the difference in these two array declarations?

Ok I realize my original question was really bad. Here goes take 2. Our goal is to replicate the behaviour the folowing commands in Perl using only "splice".
my #arr = qw (A B C D);
#arr = ();
#or
#arr;
#replace the commands above.
I used
splice(#arr)
to replace the command. But I was wondering if there's a difference between writing
#arr = ();
and
#arr;
my #arr = ();
is a cluttered, inefficient way of writing
my #arr;
What it does: It creates a new empty lexically-scopped array named #arr.
Lexically-scoped means #arr is only visible (i.e. can only be used) within the inner-most curlies (or file) that contains it.
Assigning an empty list to array empties it, but newly created arrays are guaranteed to be empty already.
my #arr = qw( A B C D );
is equivalent to
my #arr = split(' ', q( A B C D ));
It's a convenient (i.e. shorter) way of writing
my #arr = ( 'A', 'B', 'C', 'D' );
What it does: It creates a new lexically-scopped array named #arr, and assigns four strings (A, B, C and D) to it.
You'd get the same result from
my #arr;
$arr[0] = 'A';
$arr[1] = 'B';
$arr[2] = 'C';
$arr[3] = 'D';
(#arr, #arr = ( )) makes no sense. It amounts to #arr = ().
my #arr = qw (A B C D); my #arr = (); makes no sense. It amounts to my #arr;.
my #arr = (); declares a perl variable #arr as local to the scope of the enclosed block. The declaration in the title: #a, #a = () defines #a globally. These links can provide you some help:
How should I use the "my" keyword in Perl?
Why declare Perl variable with "my" at file scope?
and from perldoc:
https://perldoc.perl.org/functions/my.html
if you used modules like use strict, your program would fail if variable were not defined with my.
my #arr = qw(foo bar) is the Perl style. It is more or less convention of the Perl language (e.g. how Python code is Pythonic).
my #arr = declares an array and assigns a list to it.
In your first example, the list is one formed by qw, which "Evaluates to a list of the words extracted out of STRING, using embedded whitespace as the word delimiters." So qw( A B C D ) is the list 'A','B','C','D'. Other delimiters than () can be used, just like with other quote-type operators.
In your second example, you are assigning an empty list to the new array. To make it equivalent to the first example without using qw, it could be:
my #arr = ('A','B','C','D');
or even:
my #arr = 'A'..'D';
qw is there for convenience; most people like it, some do not. Use whatever works for you.

Perl: Sub's arguments explain

In perl all sub's argument writting to #_ array, like this:
call_any_sub($a,$b,$c);
sub call_any_sub {
my $s_a = shift;
my $s_b = shift;
my $s_c = shift;
}
But, if i want to passed array as an argument to sub, i should use:
call_any_sub(#data_array);
sub call_any_sub {
my #data = #_;
}
Instead of similar:
call_any_sub(#data_array);
sub call_any_sub {
my #data = shift;
}
So, why #data_array replaces the array of arguments and not written in it (as expected)?
One can only pass a list of scalars to a subroutine (and that's all they can return). After all, the arguments are presented to the sub as an array (#_), and arrays can only contains scalars.
You can either (inefficiently) recreate the array in the sub
sub foo {
my #bars = #_;
say for #bars;
}
foo(#bars);
or you can pass a reference to the array
sub foo {
my ($bars) = #_;
say for #$bars;
}
foo(\#bars);
You need to understand what shift does.
The shift/unshift pair of commands are parallel to the pop/push pair of commands. All of these commands operate on arrays. By default, shift (and only shift) assumes the #_ array when called in a subroutine and #ARGV when called in the main program. This means the following two statements are identical in a subroutine:
my $foo = shift #_; # Explicit Argument
my $foo = shift # Implicit Argument
Perl's parameter passing is an interesting concept because it doesn't really do named parameter passing like almost all other programs. Instead, everything is passed as one long list of scalars. This makes it hard when you aren't passing in a scalar.
It works okay if I am only passing in a single hash or array:
munge_hash ( %foo );
sub munge_hash {
my %hash = #_;
...
}
And, you have to be careful if you're passing in multiple arguments and an array. In this case, the array must be the last in your list of arguments:
my $foo = "floop";
my $bar = "bloop";
my #array = qw(loop coop soop);
munge_this ( $foo, $bar, #array );
sub munge_this {
say join ":", #_; # Prints "floop:bloop:loop:coop:soop"
my $var1 = shift # floop
my $var2 = shift # bloop
my #arry = #_ # The rest is the array passed.
However, things really fall apart if you're passing in multiple arrays or hashes. All of the elements get merged into a single list of scalars represented by #_.
munge_two_arrays ( #foo, #bar );
sub munge_two_arrays {
# Problem! Elements of both arrays are in #_.
# How do I separate them out?
}
Thus, it is common not to pass in a whole array, but an array reference:
munge_two_arrays( \#foo, \#bar ); # These are array references
sub munge_two_arrays {
my $array1_ref = shift;
my $array2_ref = shift;
my #array1 = #{ $array1_ref } # Dereference array references to make arrays
my #array2 = #{ $array2_ref } # Dereference array references to make arrays
}
This keeps the values of the two arrays from getting merged into a single #_.

Updated: Initialise and Clear multiple hash in one line

How can I Initialise and clear multiple hash in one line.
Ex:
my %hash1 = ();
my %hash2 = ();
my %hash3 = ();
my %hash4 = ();
to
my ( %hash1, %hash2, %hash3, %hash4 ) = ?
It appears (from your comments) that you really want to empty hashes that already have stuff in them. You can do it like this:
(%hash1,%hash2,%hash3) = ();
Complete example:
use strict;
use warnings;
my %hash1 = ('foo' => 1);
my %hash2 = ('bar' => 1);
my %hash3 = ('baz' => 1);
(%hash1,%hash2,%hash3) = ();
print (%hash1,%hash2,%hash3);
A variable declaration always gives you an empty variable, so there is no need to set it to empty. This is true even in a loop:
for (0..100)
{
my $x;
$x++;
print $x;
}
This will print 1 over and over; even though you might expect $x to retain its value, it does not.
Explanation: Perl allows list assignment like ($foo,$bar) = (1,2). If the list on the right is shorter, any remaining elements get assigned undef. Thus assigning the empty list to a list of variables makes them all undefined.
Another useful way to set a bunch of things is the x operator:
my ($x,$y,$z) = (100)x3;
This sets all three variables to 100. It doesn't work so well for hashes, though, because each one needs a list assigned to it.
It's as simple as doing
my ( %hash1, %hash2, %hash3, %hash4 );
and they will not contain any keys or values at that point.
The same technique applies to scalars and arrays.
To undef multiple hashes, you could do
undef %$_ for ( \%hash1, \%hash2 );
You can initialize it as:
my %hash1 = %hash2 = %hash3 = %hash4 = ();
You do not need to assign anything to a new variable in order to assure it is empty. All variables are empty, if nothing has been assigned to them.
my %hash; # hash contains nothing
%hash = () # hash still contains nothing
The only time it would be useful to assign the empty list to a hash is if you want to remove previously assigned values. And even then, that would only be a useful thing to do if it could not already be solved by applying the correct scope restriction to the hash.
my (%hash1, %hash2);
while (something) {
# some code
(%hash1,%hash2) = (); # delete old values
}
Emptying the hashes. Better written as:
while (something) {
my (%hash1, %hash2); # all values are now local to the while loop
# some code
}

Dereferencing a list reference in hash element

Can someone finish this for me and explain what you did?
my %hash;
#$hash{list_ref}=[1,2,3];
#my #array=#{$hash{list_ref}};
$hash{list_ref}=\[1,2,3];
my #array=???
print "Two is $array[1]";
#array = #{${$hash{list_ref}}};
(1,2,3) is a list.
[1,2,3] is a reference to a list an array (technically, there's no such thing in Perl as a reference to a list).
\[1,2,3] is a reference to a reference to an array.
$hash{list_ref} is a reference to a reference to an array.
${$hash{list_ref}} is a reference to an array.
#{${$hash{list_ref}}} is an array.
Since a reference is considered a scalar, a reference to a reference is a scalar reference, and the scalar dereferencing operator ${...} is used in the middle step.
Others have pretty much already answered the question, but more generally, if you are ever confused about a data structure, use Data::Dumper. This will print out the structure of the mysterious blob of data, and help you parse it.
use strict; #Always, always, always
use warnings; #Always, always, always
use feature qw(say); #Nicer than 'print'
use Data::Dumper; #Calling in the big guns!
my $data_something = \[1,2,3];
say Dumper $data_something;
say Dumper ${ $data_something };
Let's see what it prints out...
$ test.pl
$VAR1 = \[
1,
2,
3
];
$VAR1 = [
1,
2,
3
];
From the first dump, it appears that $data_something is a plain scalar reference to an array reference. That lead me to add the second Dumper after I ran the program the first time. That showed me that ${ $data_something } is now a reference to an array.
I can now access that array like this:
use strict; #Always, always, always
use warnings; #Always, always, always
use feature qw(say); #Nicer than 'print'
use Data::Dumper; #Calling in the big guns!
my $data_something = \[1,2,3];
# Double dereference
my #array = #{ ${ $data_something } }; #Could be written as #$$data_something
for my $element (#array) {
say "Element is $element";
}
And now...
$ test.pl
Element is 1
Element is 2
Element is 3
It looks like you meant:
my $hash{list_ref} = [1,2,3];
and not:
$hash{list_ref} = \[1,2,3];
That latter one got you an scalar reference of a array reference which really doesn't do you all that much good except add confusion to the situation.
Then, all you had to do to refer to a particular element is $hash{list_ref}->[0]. This is just a shortcut for ${ $hash{list_ref} }[0]. It's easier to read and understand.
use strict;
use warnings;
use feature qw(say);
my %hash;
$hash{list_ref} = [1, 2, 3];
foreach my $element (0..2) {
say "Element is " . $hash{list_ref}->[$element];
}
And...
$ test.pl
Element is 1
Element is 2
Element is 3
So, next time you are confused about what a particular data structure looks like (and it happens to the best of us. Well... not the best of us, It happens to me), use Data::Dumper.
my %hash;
#$hash{list_ref}=[1,2,3];
#Putting the list in square brackets makes it a reference so you don't need '\'
$hash{list_ref}=[1,2,3];
#If you want to use a '\' to make a reference it is done like this:
# $something = \(1,2,3); # A reference to a list
#
# or (as I did above)...
#
# $something = [1,2,3]; # Returns a list reference
#
# They are the same (for all intent and purpose)
print "Two is $hash{list_ref}->[1]\n";
# To make it completely referenced do this:
#
# $hash = {};
# $hash->{list_ref} = [1,2,3];
#
# print $hash->{list_ref}[1] . "\n";
To get at the array (as an array or list) do this:
my #array = #{ $hash{list_ref} }
[ EXPR ]
creates an anonymous array, assigns the value returned by EXPR to it, and returns a reference to it. That means it's virtually the same as
do { my #anon = ( EXPR ); \#anon }
That means that
\[ EXPR ]
is virtually the same as
do { my #anon = ( EXPR ); \\#anon }
It's not something one normally sees.
Put differently,
1,2,3 returns a list of three elements (in list context).
(1,2,3) same as previous. Parens simply affect precedence.
[1,2,3] returns a reference to an array containing three elements.
\[1,2,3] returns a reference to a reference to an array containing three elements.
In practice:
my #data = (1,2,3);
print #data;
my $data = [1,2,3]; $hash{list_ref} = [1,2,3];
print #{ $data }; print #{ $hash{list_ref} };
my $data = \[1,2,3]; $hash{list_ref} = \[1,2,3];
print #{ ${ $data } }; print #{ ${ $hash{list_ref} } };

Demystifying the Perl glob (*)

In this question the poster asked how to do the following in one line:
sub my_sub {
my $ref_array = shift;
my #array = #$ref_array;
}
which with my knowledge of the basic Perl magic I would avoid by simply using something like:
sub my_sub {
my $ref_array = shift;
for (#$ref_array) {
#do somthing with $_ here
};
#use $ref_array->[$element] here
}
However in this answer one of SO's local monks tchrist suggested:
sub my_sub {
local *array = shift();
#use #array here
}
When I asked
In trying to learn the mid-level Perl
magic, can I ask, what is it that you
are setting to what here? Are you
setting a reference to #array to the
arrayref that has been passed in? How
do you know that you create #array and
not %array or $array? Where can I
learn more about this * operator
(perlop?). Thanks!
I was suggested to ask it as a new post, though he did give nice references. Anyway, here goes? Can someone please explain what gets assigned to what and how come #array gets created rather than perhaps %array or $array? Thanks.
Assignment to a glob
*glob = VALUE
contains some magic that depends on the type of VALUE (i.e., return value of, say, Scalar::Util::reftype(VALUE)). If VALUE is a reference to a scalar, array, hash, or subroutine, then only that entry in the symbol table will be overwritten.
This idiom
local *array = shift();
#use #array here
works as documented when the first argument to the subroutine is an array reference. If the first argument was instead, say, a scalar reference, then only $array and not #array would be affected by the assignment.
A little demo script to see what is going on:
no strict;
sub F {
local *array = shift;
print "\#array = #array\n";
print "\$array = $array\n";
print "\%array = ",%array,"\n";
print "------------------\n";
}
$array = "original scalar";
%array = ("original" => "hash");
#array = ("orignal","array");
$foo = "foo";
#foo = ("foo","bar");
%foo = ("FOO" => "foo");
F ["new","array"]; # array reference
F \"new scalar"; # scalar reference
F {"new" => "hash"}; # hash reference
F *foo; # typeglob
F 'foo'; # not a reference, but name of assigned variable
F 'something else'; # not a reference
F (); # undef
Output:
#array = new array
$array = original scalar
%array = originalhash
------------------
#array = orignal array
$array = new scalar
%array = originalhash
------------------
#array = orignal array
$array = original scalar
%array = newhash
------------------
#array = foo bar
$array = foo
%array = FOOfoo
------------------
#array = foo bar
$array = foo
%array = FOOfoo
------------------
#array =
$array =
%array =
------------------
#array = orignal array
$array = original scalar
%array = originalhash
------------------
Additional doc at perlmod and perldata. Back in the days before references were a part of Perl, this idiom was helpful for passing arrays and hashes into subroutines.
With my admittedly less-than-wizard knowledge of Perl, I'll venture an answer. The * operator assigns the symbol table entry. As I understand it, #array, %array, and $array all refer to the same symbol table entry for the string 'array', but to different fields in that entry: the ARRAY, HASH, and SCALAR fields. So assigning local *array = shift; actually assigns the entire local symbol table entry for 'array' (including the ARRAY, HASH, and SCALAR fields) to what was passed used in the caller.