Why does map return an empty array? - perl

I have a problem in Perl I don't understand. I stripped it down to this very short code.
Why does Perl's map function return an empty array? Shouldn't it return an array with 9 undefs?
sub mySub{
return;
}
my #arr = (1 .. 9);
my #arr2 = map( mySub($_), #arr );
print #arr . ' ' . #arr2, "\n";
It prints "9 0".
It is probably something simple, but perldoc is not helping.

The more general answer to your question is this: when return is used without an argument, the value it returns depends on the calling context:
list context returns an empty list
scalar context returns an undefined value
For example:
use strict;
use warnings;
use Data::Dumper;
my (#list);
sub mySub { return }
#list = map( mySub($_), 1..2); print Dumper(\#list);
#list = map(scalar mySub($_), 1..2); print Dumper(\#list);
Output:
$VAR1 = [];
$VAR1 = [
undef,
undef
];

You subroutine is not returning undef, it is returning an empty list. 9 times and empty list is still an empty list.
Try explicitly returning undef and the output will be different.

Try this
use strict;
use warnings;
sub mySub{
return undef;
}
my #arr = (1,2,3,4,5,6,7,8,9);
my #arr2 = map(&mySub, #arr);
print #arr." ".#arr2;
If you need to get list containing undefs, you need to return undef explicitly. The thing is that map calls your mySub in array context (check what wantarray gives you from this sub). return statement essentially gives back an empty list each time your sub is called, which results in empty array in total

Related

Perl reference not printing the expected value

This is my program but why not it is printing my array values instead.
use strict;
use warnings;
use Data::Dumper;
my (#arr1,#arr2) = ([1,1,1,2,3,4],[5,5,5,6,9,87]);
my #arr3 = [\#arr1,\#arr2];
foreach (#arr3){
foreach (#$_){
print $_;
}
}
Output:
ARRAY(0x556414c6b908)ARRAY(0x556414c6b7e8)
but why not it is printing my array values instead.
Because the values are array references. To print the inner values, use dereference:
print #{ $array_ref };
For complex structures (arrays of arrays), you can use Data::Dumper:
use Data::Dumper;
print Dumper($array_ref);
But it still wouldn't work. You can't assign to several arrays at once. The first array gets all the values, the remaining arrays stay empty.
Documented in perlsub:
Do not, however, be tempted to do this:
(#a, #b) = upcase(#list1, #list2);
Like the flattened incoming parameter list, the return list is also
flattened on return. So all you have managed to do here is stored
everything in #a and made #b empty.
First of all, you weren't assigning anything to #arr2. You used something like the following to try to assign to #arr2:
(#arr1, #arr2) = ...;
However, Perl has no way to know how many scalars to assign to #arr1 and how many to assign to #arr2, so it assigns them all to #arr1. Use two different assignments instead.
Secondly, [ ] creates an array and returns a reference to it, so
my #arr1 = [1,1,1,2,3,4];
assigns a single scalar (a reference) to #arr1. This is what you are printing. You want
my #arr1 = (1,1,1,2,3,4);
Same goes for #arr2 and #arr3.
Therefore, your code should be
use strict;
use warnings;
use feature qw( say );
my #arr1 = (1,1,1,2,3,4);
my #arr2 = (5,5,5,6,9,87);
my #arr3 = (\#arr1,\#arr2);
for (#arr3) {
say join ", ", #$_;
}
or
use strict;
use warnings;
use feature qw( say );
my #arr3 = ([1,1,1,2,3,4],[5,5,5,6,9,87]);
for (#arr3) {
say join ", ", #$_;
}

understanding data structures in perl

I'm trying to understand the 'Common Mistake' section in the perldsc documentation. What is the author trying to convey when he mentions:
The two most common mistakes made in constructing something like an array of arrays is either accidentally counting the number of elements or else taking a reference to the same memory location repeatedly. Here's the case where you just get the count instead of a nested array:
for my $i (1..10) {
my #array = somefunc($i);
$AoA[$i] = #array; # WRONG!
}
From what I understand is that when it iterate it will take the first value of (1..10) which is 1 and will pass it to a function like this:
my #array = somefunc(1);
Since that function is not defined, I'll create the logic.
sub somefunc {
my $a = shift;
print $a * $a;
}
which will essentially do this:
1 * 1
and the result is '1'.
To my understanding my #array will look like:
#array = ('1');
And the next line will do:
$AoA[$i] = #array;
I'm assuming that $AoA[$1] is an anonymous array ( he/she didn't declare with 'my', btw) and the #array will be the first element of the this anonymous array which the author said it' WRONG. And the for each loop with iterate to '2'.
somefunc(2);
Which will be '4' and passed to:
$AoA[$i] = #array
What is the point of the author with this code which is wrong. I'm trying to understand what is wrong but more importantly, I'm trying to understand the code. Any help will be appreciated.
UPDATE
I think I understand why this is a common mistake because when I use print and Dumper, I can visually see what the author is trying to convey, here is the revised code.
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
for my $i (1..10) {
my #AoA;
my #array = somefunc($i);
print "The array is Dumper(#array)\n";
$AoA[$i] = #array; # WRONG!
print Dumper($AoA[$i]);
}
sub somefunc {
my $a = shift;
return $a * $a;
}
In the Common Mistakes paragraph of perldoc perldsc, he/she states
Here's the case where you just get the count instead of a nested array:
Below is the output of the Dumper.
The array is Dumper(1)
$VAR1 = 1;
The array is Dumper(4)
$VAR1 = 1;
The array is Dumper(9)
$VAR1 = 1;
The array is Dumper(16)
$VAR1 = 1;
The array is Dumper(25)
$VAR1 = 1;
The array is Dumper(36)
$VAR1 = 1;
The array is Dumper(49)
$VAR1 = 1;
The array is Dumper(64)
$VAR1 = 1;
The array is Dumper(81)
$VAR1 = 1;
The array is Dumper(100)
$VAR1 = 1;
So I'm assuming that the repeated
$VAR1 = 1;
is the count and not the nested array.
The author did indicate that if the count is what I truly want then to rewrite the code like this:
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
for my $i (1..10) {
my #count;
my #array = somefunc($i);
print "The array is Dumper(#array)\n";
$count[$i] = scalar #array;
print Dumper($count[$i]);
}
sub somefunc {
my $a = shift;
return $a * $a;
}
But the documentation didn't tell me how to get the nested array?
UPDATE
Correct me if I am wrong but I rewrote the code to get the nested array:
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my #count;
my #new_array;
for my $i (1..10) {
#my #count;
my #array = somefunc($i);
push #new_array, [#array];
}
sub somefunc {
my $a = shift;
return $a * $a;
}
print Dumper(\#new_array);
Which printed
$VAR1 = [
[
1
],
[
4
],
[
9
],
[
16
],
[
25
],
[
36
],
[
49
],
[
64
],
[
81
],
[
100
]
];
In the following statement:
$AoA[$i] = #array;
the #array is referenced in a scalar context, yielding a number of its elements. The context is imposed by LHS, that is $AoA[$i] which is a single element of the #AoA array.
In Perl, there are no array of arrays in a strict sense. These are emulated essentially by either "flatten" arrays or array with references. For the latter, you would need to use take reference operator as in:
$AoA[$i] = \#array;
For the starter, you may find, that Data::Dumper is very handy in examining complex data stuctures such as arrayrefs and hashrefs.
Perl is polymorphic, which means that it deals with different data types transparently, and makes what is usually a pretty good guess on how to deal with something. This makes the programmer's work much easier because it is not strongly typed like other languages.
So for example if $i is the number 4, you can do this:
print $i + 1;
and you will see a 5 - pretty logical, right?
and if you do this:
print "I am " , $i , " years old";
You will see "I am 4 years old" - in this case perl says "you are operating in list context, so I will treat $i as a string. No need to convert the number into a string as many other languages insist.
So when you assign
$AoA[$i] = #array;
The way it treats this depends on the context. In scalar context, it will set $AoA[$i] to be the length of the array.
For more information about scalar vs list context, read this answer:
http://perl.plover.com/context.html
Your example isn't very useful in understanding what is going on here as your subroutine always returns "1" - the result of calling print(). If you replace the print() with return() then you will at get different values (1, 4, 9, etc).
But the next line of code:
$AoA[$i] = #array;
Will always assign 1 to the element of #Aoa. That's because You are assigning an array (#array) to a scalar variable ($AoA[$i]) and when you evaluate an array in a scalar context, you get the number of elements in the array.
Now, as your #array only ever has a single element, you could do this:
$AoA[$i] = $array[0];
But that's not really building an array of arrays. What you really want to do is to get a reference to an array.
$AoA[$i] = \#array;
This would be more useful if your subroutine returned more than one value.
sub somefunc {
# Used $x instead of $a as $a has a special meaning in Perl
my $x = shift;
return ($x * $x, $x * $x * $x);
}
for my $i (1..10) {
my #array = somefunc($i);
$AoA[$i] = \#array;
}
As useful tool for exploring this is Data::Dumper. Try adding:
use Data::Dumper;
To the top of your code and:
print Dumper #AoA;
After the foreach loop to see the different data structures that you get back.

Perl: Special array #_ is not really an alias?

The special array, #_ , where all the arguments passed to a function are present, is actually an alias to the arguments passed. Hence, any change we make directly to this special array #_ will reflect in the main as well. This is clear.
#!/usr/bin/perl
use warnings;
use strict;
$\="\n";
sub func {
print \#_;
$_++ for(#_);
}
my #arr=(2..4);
print \#arr;
func(#arr);
print "#arr";
For the above program, I expected the reference of #arr and #_ to point to the same location since it is an alias. But it is not so.
On running the above:
ARRAY(0x1b644d0)
ARRAY(0x1b644e0)
3 4 5
If they are pointing to 2 different locations, how the changes done in #_ is reflecting in #arr?
Am I seeing something wrong? Please advice.
This might answer you question:
use warnings;
use strict;
$\="\n";
sub func {
print \#_;
$_++ for(#_);
print \$_ for #_;
}
my #arr=(2..4);
print \#arr;
func(#arr);
print "#arr";
print \$_ for #arr;
Output
ARRAY(0x17fcba0)
ARRAY(0x1824288)
SCALAR(0x17fcc48)
SCALAR(0x18196f8)
SCALAR(0x1819710)
3 4 5
SCALAR(0x17fcc48)
SCALAR(0x18196f8)
SCALAR(0x1819710)
As you see, individual arguments have the same address but the container is not the same. If you push an item to #_ in func the #arr will not change (so you can do shift in funct). So, each argument is an alias and array elements are passed as individual items. #_ contains all items passed into the subroutine. If you want to modify an array argument you need to pass it by reference.
#_ isn't aliased; its elements are.
Remember that
func(#arr);
is the same as
func($arr[0], $arr[1], ...);
because the only thing that can be passed to a sub is a list of scalars, and an array evaluates to a list of its elements in list context.
So that means
func(#arr);
is basically the same as
local #_;
alias $_[0] = $arr[0];
alias $_[1] = $arr[1];
...
&func;
Changing the elements of #_ will change elements of #arr, but adding and removing elements of #_ won't change #arr since they are different arrays.
>perl -E"#a=(4..6); sub { $_[0] = '!'; say #_; }->(#a); say #a;"
!56
!56
>perl -E"#a=(4..6); sub { splice(#_,0,1,'!'); say #_; }->(#a); say #a;"
!56
456

Pass by reference in perl

use warnings;
use strict;
my #array = (1,2,3,4,5);
my $v = 1;
sub by_ref
{
my ($array_ref,$v) = #_;
#$array_ref = (0,0,0);
print "Array inside by_ref: #$array_ref\n";
}
by_ref(\#array,$v);
print "Array changed: #$array\n";
I'm passing #array by reference(I'm assuming I'm doing it right). I want the changes made in the sub routine on #arraybe reflected in the calling sub routine. I don't know where I have gone wrong.
Thank you in advance.
You are printing the array reference outside the subroutine too, which is wrong. The scope of array reference is limited to the subroutine only.
So you should change your last line to print only #array not #$array.
Like:
print "Array changed: #array\n";
Just change to
print "Array changed: #array\n";
and it should be ok

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} } };