What exactly mean the ${...} in the perl? - arrays

Thinking about the next. Have a LIST
qw(a b c);
now, assign the LIST into nameless (anonymous) ARRAY
[ qw(a b c) ]
so the next
use 5.016;
use warnings;
use diagnostics;
my $x = [ qw(a b c) ];
say ref $x; #ARRAY - the $x is an ARRAY reference, and
say $x->[1]; #prints "b", and
say [ qw(a b c) ]->[1]; #works too
but what happens now?
use 5.016;
use warnings 'all';
use diagnostics;
say ${[ qw(a b c) ]}[1];
it prints b, but
my $y = ${[ qw(a b c) ]};
is an error,
Not a SCALAR reference at pepe line 6 (#1)
(F) Perl was trying to evaluate a reference to a scalar value, but found
a reference to something else instead. You can use the ref() function
to find out what kind of ref it really was. See perlref.
Uncaught exception from user code:
Not a SCALAR reference at pepe line 17.
So, whats mean the contruction ${.... }
It "works" in the say (prints the second element of the anonymous array), but don't understand why
but can't assign it into variable
And the hint from the diagnostics is not very helpful, because how I should use the ref when I can't assign? What I missed from the perlref?

${ EXPR1 }[ EXPR2 ] is an array index dereference. It returns the element at the index returned by EXPR2 of the array referenced by the reference returned by EXPR1.
${ $array_ref }[ ... ] is to array references as $array[...] is to arrays.
${ EXPR } that's not followed by [ or { is a scalar dereference. It returns the scalar referenced by the reference returned by EXPR.
${ $scalar_ref } is to scalar references as $scalar is to scalars.
As you can see, when dealing with a reference, you can use the same syntax as you normally would, except that you replace the name of the variables with {$ref} (keeping the leading sigil).
As such, #{ $array_ref } is to array references as #array is to arrays.
say #{[ qw(a b c) ]};
This is the essence of the chart in my earlier post Mini-Tutorial: Dereferencing Syntax. See also:
References quick reference
perlref
perlreftut
perldsc
perllol
Oops, I thought you had
say ${[ qw(a b c) ]}; # Want to print a b c
You have
my $y = ${[ qw(a b c) ]};
You want
my $y = [ qw(a b c) ];
[] creates an array and a reference to that array, and returns the latter, kinda like
my $y = do { my #anon = qw(a b c); \#a };

Given an array #arr and an arrayref $aref = \#arr, then inside the following groups of expressions all lines are equivalent:
Accessing the whole array:
# arr
#{$aref}
Accessing a single scalar in the array:
$ arr [$i]
${$aref}[$i]
$ aref->[$i]
Accessing a slice of entries:
# arr [$i .. $j]
#{$aref}[$i .. $j]
(the spaces are included for alignment and are not recommended for actual code).
The ${}, #{}, … are circumfix dereference operators. However, accessing a single scalar changes the sigil from % or # to $. Without references, this makes total sense. With them, it's just slightly complicated, until you read perlreftut (esp. the two reference usage rules).

With the
${$ar}[0]
you said to perl: take $ar as arrayref and return me 1st element from the array to what the reference $ar points.
With the construction
${$sr}
you saying to perl: take the $sr as SCALAR REF and return the value of the scalar to what the reference $sr points.
Therefore, the answer to your question from the comment: When the $ar is an array-ref, WHAT IS the ${$ar}? is:
When the $ar is an $array-ref, the ${$ar} is an ERROR,
because you said to perl - take the scalar-ref, but the $ar is NOT scalar-ref (it is arrayref).
The next example show your constructions clearly:
use 5.012;
use warnings;
my #arr = qw(a b c);
my $aref = \#arr;
my $myval = "VALUE";
my $sref = \$myval;
say $aref->[0];
say ${$aref}[0];
say ${$sref}; #your construction - here CORRECTLY points to an scalar
#say ${$aref} #ERROR because the ${$xxx} mean: take scalar ref, but the $aref is array ref.

Related

A simple hashing-array-loop, I get error warnings even though it works, why is that?

I have prepared a short loop that looks like this:
#array = ("a", "b", "c", "d", "e");
$count=0;
print "#array\n";
foreach $string(#array){
$number=$count++ +1 ;
$string{$link} = $number;
print "$string\n$string{$link}\n";
}
It should come out as
a
1
b
2
...
and so on.
It works but when I print it out on the terminal, I get warning messages:
Use of uninitialized value $link in hash element at ./hashing_an_array.pl line 11.
Use of uninitialized value $link in hash element at ./hashing_an_array.pl line 12.
a
1
Use of uninitialized value $link in hash element at ./hashing_an_array.pl line 11.
Use of uninitialized value $link in hash element at ./hashing_an_array.pl line 12.
b
2
...
etc
Why do I get these messages? I just wanted to know so that even though it works, I am sure I know what I am doing.
It happens because you never assigned a value to $link so it's default value is undef. Trying to use undef as a hash key generates a warning message because it's invalid.
Read perldata http://perldoc.perl.org/perldata.html
As noted in the other answers $link is undeclared and you should use strict; which would tell you this:
Global symbol "$link" requires explicit package name (did you forget to declare "my $link"?)
The following snippet is probably something like what you were after:
#!/usr/bin/perl
use strict;
use warnings;
my #array = qw(a b c d e);
my $count = 0;
my %link;
foreach my $string (#array) {
$count++;
$link{$string} = $count;
print "$string\n";
print "$link{$string}\n";
}
Although you should probably rename your hash and iteration variable to something that better reflects your intent, like for example using %count_for and $letter if you were doing letter counts.

Perl: equivalent of "ubound" in VBA

Now that on day 2 of Perl I see that arrays start with element(0) too, how do I get the last index of an array like ubound in VBA rather than the size of it using scalar(#array)?
Is the use of $size = $#array a good way or is there something similar to scalar(#array)?
Perl's arrays always start empty.
my #array; # equivalent
my #array = (); #
To get the highest index, use $#array.
my #array = qw(a b c);
print $#array; # 2
If the array is empty, $#array will be -1.

How can I create a variable array name in Perl?

Array #p is a multiline array, e.g. $p[1] is the second line.
This code will explain what I want:
$size=#p; # line number of array #p
for($i=0; $i<$size; $i++)
{
#p{$i}= split(/ +/,$p[$i]);
}
I want the result should be like this:
#p0 = $p[0] first line of array #p goes to array #p0;
#p1 = $p[1] second line of array #p goes to array #p1;
...
...
and so on.
But above code does not work, how can I do it?
It is a bad idea to dynamically generate variable names.
I suggest the best solution here is to convert each line in your #p array to an array of fields.
Lets suppose you have a better name for #p, say #lines. Then you can write
my #lines = map [ split ], <$fh>;
to read in all the lines from the file handle $fh and split them on whitespace. The first field of the first line is then $lines[0][0]. The third field of the first line is $lines[0][2] etc.
First, the syntax #p{$i} accesses the entry with the key $i in a hash %p, and returns it in list context. I don't think you meant that. use strict; use warnings; to get warned about undeclared variables.
You can declare variables with my, e.g. my #p; or my $size = #p;
Creating variable names on the fly is possible, but a bad practice. The good thing is that we don't need to: Perl has references. A reference to an array allows us to nest arrays, e.g.
my #AoA = (
[1, 2, 3],
["a", "b"],
);
say $AoA[0][1]; # 2
say $AoA[1][0]; # a
We can create an array reference by using brackets, e.g. [ #array ], or via the reference operator \:
my #inner_array = (1 .. 3);
my #other_inner = ("a", "b");
my #AoA = (\#inner_array, \#other_array);
But careful: the array references still point to the same array as the original names, thus
push #other_inner, "c";
also updates the entry in #AoA:
say $AoA[1][2]; # c
Translated to your problem this means that you want:
my #pn;
for (#p) {
push #pn, [ split /[ ]+/ ];
}
There are many other ways to express this, e.g.
my #pn = map [ split /[ ]+/ ], #p;
or
my #pn;
for my $i ( 0 .. $#p ) {
$pn[$i] = [ split /[ ]+/, $p[$i] ];
}
To learn more about references, read
perlreftut,
perldsc, and
perlref.

How to retrieve an array from a hash that has been passed to a subroutine in perl

I am trying to write a subroutine that takes in a hash of arrays as an argument. However, when I try to retrieve one of the arrays, I seem to get the size of the array instead of the array itself.
my(%hash) = ( );
$hash{"aaa"} = ["blue", 1];
_subfoo("test", %hash);
sub _subfoo {
my($test ,%aa) = #_;
foreach my $name (keys %aa) {
my #array = #{$aa{$name}};
print $name. " is ". #array ."\n";
}
}
This returns 2 instead of (blue, 1) as I expected. Is there some other way to handle arrays in hashes when in a subroutine?
Apologies if this is too simple for stack overflow, first time poster, and new to programming.
You're putting your #array array into a scalar context right here:
print $name. " is ". #array ."\n";
An array in scalar context gives you the number of elements in the array and #array happens to have 2 elements. Try one of these instead:
print $name . " is " . join(', ', #array) . "\n";
print $name, " is ", #array, "\n";
print "$name is #array\n";
and you'll see the elements of your #array. Using join lets you paste the elements together as you please; the second one evaluates #array in list context and will mash the values together without separating them; the third interpolates #array by joining its elements together with $" (which is a single space by default).
As mu is too short has mentioned, you used the array in scalar context, and therefore it returned its length instead of its elements. I had some other pointers about your code.
Passing arguments by reference is sometimes a good idea when some of those arguments are arrays or hashes. The reason for this is that arrays and hashes are expanded into lists before being passed to the subroutine, which makes something like this impossible:
foo(#bar, #baz);
sub foo { # This will not work
my (#array1, #array2) = #_; # All the arguments will end up in #array1
...
}
This will work, however:
foo(\#bar, \#baz);
sub foo {
my ($aref1, $aref2) = #_;
...
}
You may find that in your case, each is a nice function for your purposes, as it will make dereferencing the array a bit neater.
foo("test", \%hash); # note the backslash to pass by reference
sub foo {
my ($test, $aa) = #_; # note use of scalar $aa to store the reference
while (my ($key, $value) = each %$aa)) { # note dereferencing of $aa
print "$key is #$value\n"; # ...and $value
}
}

In Perl, what is the difference between #array[1] and $array[1]?

I have been studying array slices and frankly do not see the difference between choosing #array[1] and $array[1]. Is there a difference?
#!/usr/bin/perl
#array = (1,3);
print "\nPrinting out full array..\#array\n";
print "#array\n";
print "\n";
print "Printing out \#array[1]\n";
print "#array[1]\n";
print "Printing out \$array[1]\n";
print "$array[1]\n";
print "\n\n";
This is a FAQ.
The two forms are likely to work the same way in many contexts (but not all, as you can see from the example in the FAQ), but $array[1] expresses the intent more clearly.
$ and # are called sigils: hear what the sigils tell you
When you see $ you are dealing with a single thing.
When you see # you have a list of things.
#array[ 1 ] is a slice, a list with selected elements from the #array list. You have put only an element in this slice, the second element of #array, but it's a list anyway.
$array[ 1 ] is the second element of the list, a single value, a scalar.
#hash{ 'one', 'two' } is another kind of slice: this time we sliced an hash ( %hash ), obtaining a list with values corresponding to keys one and two.
Where's the difference? Although the difference is thin, you should avoid single element slices when you want a single value. Remember that on the right hand side of an expression, single element slices behave like scalars, but when they are on the left hand side of an expression they become a list assignment: they give list context to the expression.
If still you aren't feeling comfortable with the difference between scalar and list context, please don't use single element slices in order to avoid unexpected results in certain situations ( for instance when using the line input operator < > ).
Check the docs and happy Perl.
You already have your answer from Keith and Marco: # means list, $ means scalar (single value). I have more to add that does not fit in a comment.
You do not notice the difference because you are using a slice of one element. However, try this:
use warnings;
use strict;
use v5.10; # to enable say
my #array = (1 .. 10);
say "#array[2 .. 4]"; # [2,3,4] == "3 4 5"
say "#array[1,4,7]"; # == "2 5 8"
Here's some pointers to your code.
use strict;
use warnings;
There really is no excuse for not using these two. There is hardly any circumstance where it is better -- or easier -- to not use them. This holds especially true when you are experimenting and trying to learn perl.
If you had been using warnings, you would have gotten this additional information:
Scalar value #array[1] better written as $array[1]
Which basically is exactly the answer you have been given here, albeit said in the perl compiler's terse language.
Also, using print the way you do it is hard on the eyes. Make use of perl's flexibility:
#!/usr/bin/perl
use strict;
use warnings;
my #array = (1 .. 10);
print "
Printing out full array..\#array
#array
Printing out \#array[1]
#array[1]
Printing out \$array[1]
$array[1]
";
As you can see, this will print out newlines in a WYSIWYG fashion.
There are two differences:
The «1» is evaluated in list context in the case of the array slice (#foo[1]), but in scalar context in the case of the array indexing ($foo[1]). This has no functional effect.
#foo[1] gives a warning.
Good question - here's some differences:
$a[0] = localtime; print #a; # this prints: Tue Nov 1 18:51:13 2011
#a[0] = localtime; print #a; # this prints the amount of seconds, e.g. 13
$a[0] = grep{}, qw(6 2 8); print #a; # this prints: 3
#a[0] = grep{}, qw(6 2 8); print #a; # this prints: 6
$a[0] = reverse ("a", "b"); print #a; # this prints: ba
#a[0] = reverse ("a", "b"); print #a; # this prints: b
$a[0] = ("a", "b"); print #a; # this prints: b
#a[0] = ("a", "b"); print #a; # this prints: a
It doesn't matter if the slice is [1]. You can create more examples by finding functions that give different results when evaluated in different contexts.
Explanation of the latter (4th) example:
The $ in $a[0] creates a scalar context. The context affects the way the comma operator works, creating different results:
"Binary "," is the comma operator. In scalar context it evaluates its left argument, throws that value away, then evaluates its right argument and returns that value."
http://perldoc.perl.org/perlop.html#Comma-Operator
Hence: b
To understand the line beginning with: #a[0] consider:
($a, $b, $c) = ("a", "b", "c", "d"); # here the "d" is discarded
print $a, $b, $c; # this prints: abc
($a, $b) = ("a", "b", "c"); # here the "c" is discarded
($a) = ("a", "b"); # here the "b" is discarded
($a[0]) = ("a", "b"); # here the "b" is discarded
It would appear that parentheses at the beginning of the line create a list context. This is pretty much what it says at: http://docstore.mik.ua/orelly/perl4/prog/ch02_07.htm
"Assignment to a list of scalars also provides a list context to the righthand side, even if there's only one element in the list"
# at the beginnning of a line also creates a list context:
#a[0] = ("a", "b") means evaluate the RHS in the same way as above i.e. discard the "b"

Resources