How do you reference a list in Perl? - perl

I read about scalars arrays and list. I am not sure what is meant by list. For example, (5, apple, $x, 3.14) is a list, but what is the variable actually referencing the list?
Are lists just a way to initialize arrays or is it the known data structure?

How do you reference a list in Perl?
The same as you do with anything else - with the reference operator \. See perlreftut and perlref.
my $x;
\(5, 'apple', $x, 3.14)
The expression returns
(
\ 5,
\ "apple",
\ undef,
\ 3.14
)
which is not that useful.
For example, (5, apple, $x, 3.14) is a list, but what is the variable actually referencing the list?
There is none. It is an anonymous value.
Not every value needs a variable to hold it - literals are also an important part of programs.
Are lists just a way to initialize arrays or is it the known data structure?
Read Perl array vs list.

There are three different basic data structures in Perl.
Hashes: These are key/value pairs.
Arrays: These are ordered values.
Scalars: This is a single value.
Hashes:
my %employee = (
"A001" => "Albert",
"A002" => "Bob",
"B003" => "Gary",
);
print "$employee{A001}\n"; #Prints "Albert"
print "$employee{B003}\n"; #Prints "Gary"
Arrays:
my #fruit = ("Apple", "Orange", "Banana");
print "$fruit[0]\n"; #Prints "Apple"
print "$fruit[2]\n"; #Prints "Banana"
Scalars:
my $age = "None of your business";
print "You're $age years old\n"; #Prints "You're None of your business years old
A List is merely a list of items. For example, #fruit is an array. However, I set my array to equal a list containing the names of fruits.
Technically, a list is unchangeable while an array is a data structure that can be modified.
for my $color ("red", "green", "blue") {
print "$color is an item from my list\n";
}
In the above, my for loop advances through a list:
my #list = ("red", "green", "blue");
for my $color (#list) {
print "$color is a member of my array\n";
}
The above is pretty much the same code, but now my for loop advances through an array.

On a really basic level I think understanding what an operator is helps.
This can be summed up by saying anything which is not a value, is an operator.
What is the list operator?
,
How does the list operator work?
The list operator evaluates the value on the left, then evaluates the value on the right. If the value on the right of itself also has a list operator, the associativity of the operator means the evaluations will continue until no more list operators appear or end of line.
#!usr/bin/perl
use warnings;
use strict;
my #namedlist = 1, my #namedlist2 = 2;
print #namedlist , #namedlist2;
12
Once you understand the list operator, you can then deal with the real issue of your problem:
context
For example, print supplies list context to its arguments. It expects a list, not a singular value, so it supplies the list context.
Now we know that the [], and {} operators, are the reference to an anonymous array constructor, and reference to anonymous hash constructor respectively, but I think few realise that before these there was only the list constructor operator. The list constructor operator is
()
Why does this matter? Well, because the list operator , does not know about context. It just evaluates and discards, evaluates and discards.
Supply the context by wrapping a list operator with a list constructor (), and now the list constructor captures the evaluations of the list operator so that it can return a list.
Of course you will be using the assignment operator = to assign the newly constructed list returned by the list constructor (), to a named list holder. Such as an array or a hash.
my #list = (one, 1, two, 2);
my %associatedlist = (three, 3, four, 4);
So a list is a series of evaluated values captured by the list constructor, and then usually assigned into a named list holder.
This is apparent through the reverse engineering of the reference to list constructors, [] and {}.
There being a difference between the two reference to list constructors, highlights their use as operators, perhaps descending from earlier usage of a similar operator?
The reference to list constructers, must be explicitly stated through the use of either the reference to the anonymous array constructor [], or reference to the anonymous hash constructor {}.
The list constructer () is constructing a list of values which are then generally assigned to either a named array or named associated array. Though the assignment operator = does not distinguish between its leftvalue and rightvalue, it just attempts to assign the right to the left, if the contexts are incompatible or the list sizes are of differing lengths, it then proceeds to compliment your handiwork to STDOUT accordingly.
useless use of constant in void context at roughly 1 foot from keyboard.pl

Related

Perl slices and references

I created the following slice:
my %hash = ( a => 1, b => 2, c => 3 );
my #backslashed_slice_result = \#hash{qw(a b c)};
# $backslashed... <-- originally I wrote this is a scalar, see below.
I expected this to produce an array reference to an array populated by the hash slice, equivalent to:
my $arrayref_containing_slice = [ #hash{qw(a b c)} ]; # [1, 2, 3]
But actually is doing something more like:
my #mapped_list_of_values_to_refs = map { \$hash{$_} } qw(a b c); # (\1, \2, \3)
The main point I could find in the documentation that describes this behaviour is the statement:
A slice accesses several elements of a list, an array, or a hash
simultaneously using a list of subscripts.
So is \#hash{qw(a b c)} actually a list slice, rather than a hash slice? I am surprised at the reference being taken of the values of the hash, instead of of the resulting array of values. What is it about the syntax that causes perl to apply the leading \ to the values of the hash?
Two points:
First, a hash slice does not produce an array, it produces a list of the sliced hash elements.
Second, using \ on a list produces a list of references to the elements of the first list.

Why does the goatse operator work?

The difference between arrays and lists and between list and scalar context have been discussed in the Perl community quite a bit this last year (and every year, really). I have read over articles from chromatic and friedo, as well as this recommended monks node. I'm trying now to understand the goatse operator, documented in perlsecret.
Here is some code I used to study it:
# right side gets scalar context, so commas return rightmost item
$string = qw(stuff junk things);
say $string; # things
# right side gets list context, so middle is list assigned in scalar context
$string = () = qw(stuff junk things);
say $string; # 3
# right side gets list context, so creates a list, assigns an item to $string2, and
# evaluates list in scalar context to assign to $string
$string = ($string2) = qw(stuff junk things);
say $string; # 3
say $string2; # stuff
I think I have come far enough to understand all of the list and scalar context workings. The comma operator in scalar context returns its right side, so the first example simply assigns the last item in the comma expression (without any commas) to $string. In the other examples, the assignment of the comma expression to a list puts it in list context, so a list is created, and lists evaluated in scalar context return their size.
There are 2 parts that I don't understand.
First, lists are supposed to be immutable. This is stressed repeatedly by friedo. I guess that assignment via = from list to list distributes assignments from items in one list to items in the other list, which is why in the second example $string2 gets 'stuff', and why we can unpack #_ via list assignment. However, I don't understand how assignment to (), an empty list, could possibly work. With my current understanding, since lists are immutable, the size of the list would remain 0, and then assigning the size to $stuff in examples 2 and 3 would give it the value 0. Are lists not actually immutable?
Second, I've read numerous times that lists don't actually exist in scalar context. But the explanation of the goatse operator is that it is a list assignment in scalar context. Is this not a counter-example to the statement that lists don't exist in scalar context? Or is something else going on here?
Update: After understanding the answer, I think an extra pair of parentheses helps to conceptualize how it works:
$string = ( () = qw(stuff junk things) );
Inside the parens, the = is an assignment to an 'aggregate', and so is a list assignment operator (which is different from the scalar assignment operator, and which should not be confused with "list context"; list and scalar assignment can happen in either list or scalar context). () does not change in any way. = has a return value in Perl, and the result of the list assignment is assigned to $string via the left =. Assignment to $string gives scalar context to the RHS (everything in the parens), and in scalar context the returned value of the list assignment operator is the number of items in the RHS.
You can put the RHS list assignment into list context instead:
($string) = ( () = qw(stuff junk things) );
According to perlop list assignment in list context returns the list of assigned lvalues, which here is empty since there is nothing to be assigned to in (). So here $string would be undef.
You misunderstand. Lists evaluated in scalar context do not get their size. In fact, it is all but impossible to have a list in scalar context. Here, you have a scalar assignment with two operands, a scalar variable on the left, and a list assignment on the right (given scalar context by the scalar assignment). List assignments in scalar context evaluate to the number of items on the right of the assignment.
So, in:
1 $foo
2 =
3 ()
4 =
5 ('bar')
2, a scalar assignment, gives 1 and 4 scalar context.
4, a list assignment, gives 3 and 5 list context, but nevertheless is itself in scalar context and returns appropriately.
(When = is a list assignment or a scalar assignment is determined purely from the surrounding syntax; if the left operand is a hash, array, hash slice, array slice, or in parentheses, it is a list assignment, otherwise it is a scalar assignment.)
This treatment of list assignments in scalar context makes possible code like:
while ( my ($key, $value) = each %hash ) {
where list-context each is an iterator that returns (in list context) one key and value for each call, and an empty list when done, giving the while a 0 and terminating the loop.
It helps to remember that in Perl, assignment is an expression, and that you should be thinking about the value of the expression (the value of the assignment operator), not "the value of a list".
The value of the expression qw(a b) is ('a', 'b') in list context and 'b' in scalar context, but the value of the expression (() = qw(a b)) is () in list context and 2 in scalar context. The values of (#a = qw(a b)) follow the same pattern. This is because pp_aassign, the list assignment operator, chooses to return a count in scalar context:
else if (gimme == G_SCALAR) {
dTARGET;
SP = firstrelem;
SETi(lastrelem - firstrelem + 1);
}
(pp_hot.c line 1257; line numbers are subject to change, but it's near the end of PP(pp_aassign).)
Then, apart from the value of the assignment operator is the side-effect of the assignment operator. The side-effect of list assignment is to copy values from its right side to its left side. If the right side runs out of values first, the remaining elements of the left side get undef; if the left side runs out of values first, the remaining elements of the right side aren't copied. When given a LHS of (), the list assignment doesn't copy anything anywhere at all. But the value of the assignment itself is still the number of elements in the RHS, as shown by the code snippet.
First, "list" is an ambiguous term. Even the question uses it to refer to two different things. I suspect you might be doing this without realizing it, and that this is a significant part of the cause of your confusion.
I shall use "a list value" to denote what an operator returns in list context. In contrast, "the list operator" refers the operator EXPR,EXPR,EXPR,... also known as "the comma operator"[1].
Second, you should read Scalar vs List Assignment Operator.
I guess that assignment via = from list to list distributes assignments from items in one list to items in the other list, which is why in the second example $string2 gets 'stuff', and why we can unpack #_ via list assignment.
Correct.
I've read numerous times that lists don't actually exist in scalar context.
That wording is very ambiguous. You seem to be talking about list values (which are found in memory), but scalar context only exist in the code (where operators are found).
A list/comma operator can be evaluated in scalar context.
A list value can't be returned in scalar context.
Scalar context is a context in which an operator can be evaluated.
A operator evaluated in scalar context cannot return a list. It must return a scalar. Loosely speaking, you could say a list can't be returned in scalar context.
On the other hand, a list/comma operator can be evaluated in scalar context. e.g. scalar(4,5,6). Every operator can be evaluated in any context (though it's not necessarily useful to do so).
But the explanation of the goatse operator is that it is a list assignment in scalar context.
It includes one, yes.
List values and list assignment operators are two different things. One's a value. The other is a piece of of code.
A list assignment operator, like every other operator, can be evaluated in scalar context. A list assignment operator in scalar context returns the number of scalars returned by its RHS.
So if you evaluate () = qw(a b c) in scalar context, it will return three, since qw() placed three scalars on the stack.
However, I don't understand how assignment to (), an empty list, could possibly work.
Just like the assignment ($x,$y) = qw(stuff junk things) ignores the third element returned by the RHS, () = qw(stuff junk things) ignores all elements returned by the RHS.
With my current understanding, since lists are immutable, the size of the list would remain 0
Saying "the size of the list would remain zero" for ()=qw(a b c) is like saying "the value of the scalar will remain 4" for 4+5.
For starters, there's question of which list you're talking about. The LHS returned one, the RHS returned one, and the assignment operator might return one.
The list value returned by the LHS will be 0 in length.
The list value returned by the RHS will be 3 in length.
In scalar context, the list assignment operator returns the number of scalars returned by RHS (3).
In list context, the list assignment operator returns the scalars returned by LHS as lvalues (empty list).
lists are supposed to be immutable.
If you're thinking in terms of list mutability, you took a wrong turn somewhere.[2]
Notes:
The docs call EXPR,EXPR,EXPR,... two instances of a binary operator, but it's easier to understand as a single N-ary operator, and it's actually implemented as a single N-ary operator. Even in scalar context.
It's not actually true, but let's not go any further down this wrong turn.

What does ($a,$b,$c) = #array mean in Perl?

I'd google it if I could but honestly I don't know what to search for (an inherent problem with symbol-heavy languages)!
($aSvnRemote, $aSvnLocal, $aSvnRef, $aSvnOptions) = #{$aSvnPair};
My guess is that $aSvnPair is an array of 4 values (in which case it's a very poorly named variable!) and this is just splitting it into specific variable identities...?
It's nothing more than a list assignment. The first value of the RHS is assigned to the first var on the LHS, and so on. That means
($aSvnRemote, $aSvnLocal, $aSvnRef, $aSvnOptions) = #{$aSvnPair};
is the same as
$aSvnRemote = $aSvnPair->[0];
$aSvnLocal = $aSvnPair->[1];
$aSvnRef = $aSvnPair->[2];
$aSvnOptions = $aSvnPair->[3];
The variable $aSvnPair is a reference to an array. Adding the # sigil causes the array to be referenced. In this example, the array is unpacked and it's elements are assigned to the variables on the right.
Here is an example of what is happening:
$aSvnPair= [ qw(foo bar baz xyxxy) ];
($aSvnRemote, $aSvnLocal, $aSvnRef, $aSvnOptions) = #{$aSvnPair};
After this operation, you get the following:
$aSvnRemote = "foo";
$aSvnLocal = "bar";
$aSvnRef = "baz";
$aSvnOptions = "xyxxy";
$aSvnPair should be a reference to an array so #{$aSvnPair} dereferences it. (A "reference" is the Perl equivalent of a pointer.)
The statement then assigns the values of this array to the four variables on the left-hand side, in order.
See this tutorial for some examples: Dereferencing in perl

Having difficulty in understanding a piece of Perl code

I am studying an existing Perl program, which includes the following line of code:
#{$labels->{$set}->{"train"}->{"negative"}} = (#{$labels->{$set}->{"train"}->{"negative"}}, splice(#shuffled, 0, 2000));
I am very confused on how to understand this piece of code.
It is not valid Perl as written:
#{$labels->{$set}->{"train"}->{"negative"}} = (#{$labels->{$set}->{"train"}->{"negative"}};
^
Syntax error - open parenthesis without a matching close parenthesis
If you ignore the open parenthesis, then the LHS and the RHS expressions are identical; it assigns an array value to itself. The arrows -> and {} notations mostly mean that you're dealing with an array ref at the end of a hash reference to a hash reference to a hash reference, or thereabouts. It is a nasty piece of code to have to understand, at best, but the structure may make more sense in the bigger context of the whole program (and the whole program will be considerably bigger, so I don't recommend posting it here).
Double check your copy'n'paste. If that is actually in the Perl script, then it can't be being compiled, much less executed, so you'll have to work out how and why that line is not operative.
The revised expression has the RHS:
(#{$labels->{$set}->{"train"}->{"negative"}}, splice(#shuffled, 0, 2000));
The parentheses provide an array or list context; the first term is the original array; the second term is the result of splice applied to the array #shuffled. So, the splice removes a couple thousand elements (2001?) from the array #shuffled and the expression as a whole adds the deleted elements to the end of the array identified by the complex expression on the LHS.
It would probably be more efficiently written as:
push #{$labels->{$set}->{"train"}->{"negative"}}, splice(#shuffled, 0, 2000);
It's also more economical on the typing, and a lot more economical on the brain cells.
The statement:
#{$labels->{$set}->{"train"}->{"negative"}} =
(#{$labels->{$set}->{"train"}->{"negative"}}, splice(#shuffled, 0, 2000));
Does a number of things at once. It can also be written, slightly more verbose:
my #array = #{$labels->{$set}->{"train"}->{"negative"}};
my #values = #shuffled[0..1999]; # get the first 2000 values
splice #shuffled, 0, 2000; # delete the values after use
#array = (#array, #values); # add the values to the array
#{$labels->{$set}->{"train"}->{"negative"}} = #array;
As you'll notice, the LENGTH in splice is not the number of the array element, but the length of the array, which is why the count is one off in the array slice above.
As Jonathan pointed out, it is much simpler to use push.
push #{$labels->{$set}{"train"}{"negative"}}, splice(#shuffled, 0, 2000);
Documentation: splice
$labels is a reference to a hash of hashes with three depths (HoHoH). The lookup $labels->{$set}->{"train"}->{"negative"} returns an array reference.
Hope that helps a bit ..

Modifying hash within a hash in Perl

What is the shortest amount of code to modify a hash within a hash in the following instances:
%hash{'a'} = { 1 => one,
2 => two };
(1) Add a new key to the inner hash of 'a' (ex: c => 4 in the inner hash of 'a')
(2) Changing a value in the inner hash (ex: change the value of 1 to 'ONE')
Based on the question, you seem new to perl, so you should look at perldoc perlop among others.
Your %hash keys contain scalar values that are hashrefs. You can dereference using the -> operator, eg, $hashref = {foo=>42}; $hashref->{foo}. Similarly you can do the same with the values in the hash: $hash{a}->{1}. When you chain the indexes, though, there's some syntactic sugar for an implicit -> between them, so you can just do $hash{a}{1} = 'ONE' and so on.
This question probably also will give you some useful leads.
$hash{a}{c} = 4;
$hash{a}{1} = "ONE";