my #array = #{$array_ref};
I'm not entirely sure what this array is storing. Can anyone care to explain to me what is happening? Thanks.
$array_ref presumably holds a reference to an array, which is different from an array itself. An array (named #some_array) has elements (unless it's empty). An array ref (named $some_arrayref) is a scalar value that is used to reference an actual array. The actual array may be a named array (as in, it has a variable name), or may be an anonymous array (as in, no named variable, but referred to exclusively by reference).
To use the elements held in the array referred to by $array_ref, you have to dereference it. One syntax is #$array_ref (read that as "The array (#) referred to by the scalar ($) named array_ref). I've never been a fan of jamming a bunch of sigils together (the #, $ and % symbols) when dereferencing. I feel it hampers readability of the code, particularly as the references become more complex or nested. Perl allows for curly brackets, which help to disambiguate and visually clarify what's going on. #{$array_ref} can be read as dereference as an array ( #{....} ) the array referred to by $array_ref.
From Perl's POD, have a look at perlreftut. It's a great starting point.
The code makes a top-level copy of the array referenced by $array_ref and stores it in #array.
To make a deep-level copy, use dclone from Storable:
use Storable;
#array = #{ dclone( $array_ref ) };
See perldoc Storable for details.
Storable is a standard module that is install with Perl. To see a list of all standard pargmatics and modules, see perldoc perlmodlib.
This is simply dereferencing the array ref. $array_ref contains a reference to an array, #array is set to the contents of the referenced array.
$ perl -E 'my $a = [1, 2, 3]; my #b = #{$a}; say $a; say #b'
ARRAY(0x100803ea0) # a reference to an array
123 # actual array
You need to read perlref.
In short, #array is the same array that $array_ref was pointing to. That is the most precise answer that I can give without knowing what got put into $array_ref.
$array_ref is a reference to a list / array.
so in order to dereference it in a list content and get all the contents, you use
#{$array_ref}
and this can be assigned into a different array / list like:
my #array = #{$array_ref};
Related
this question succeeds the following question: Moose: Array of Objects->loop through Attribute
I'm struggling to implement the grep syntax into a List::Compare Object:
my #aIdentList=("z003","t302","p032");
my $lc=List::Compare->new('-u',\#aIdentList,\#{(grep {$_->Identifier}#aArray1)});
my #unique=$lc->get_unique;
\#{(grep {$_->Identifier}#aArray1)}
This part is weird. You are trying to dereference a list via #{}. That doesn't work.
The grep returns a list already. You do not need to use parenthesis () to construct a new list. Perl will ignore them. Then your #{} is simply wrong. You need a new array reference. That's []. It will construct a new array ref from the list that grep returns. That's already enough to pass to List::Compare->new. The backslash \ is only needed if you want to take a reference of something, but you now already have a reference.
But you actually do not want to grep here. You want to map!
This is what your code should look like.
List::Compare->new( '-u', \#aIdentList, [ map { $_->Identifier } #aArray1 ] )
grep will filter out every element of the list you pass in where the block does not return a true value. Since all objects in #aArray1 (typing this is horrible!) have an Identifier property, this will let all elements through. The second array ref arg to new will then be a list of objects. That's not what you want, because you'd be comparing apples to oranges.
Instead, you need to use map, which will pass the return value of the block for each element. It's like an inline foreach loop. Then your second list will be the actual identifiers of the objects, and not the objects themselves.
hash_test.pl
#a=("f","a","b");
$K{"f"}{"aa"}=1;
$K{"a"}{"aa"}=1;
$k{"b"}{"bb"}=1;
foreach(#a){
#c= sort keys %{$k{$_}};
}
print "#c\n";
foreach(#c) {...}
perl hash_test.pl
bb
I want to keep the keys of the hash into an array, so that I can use the array as an input for the following statements.
But it seemed that the assay #c just only hold the last element.
Could anyone tell me why or help me to improve the script?
You assign the array every time in the foreach, thus overwriting it every time. So you end up with only having the last thing assigned to it. If you move the print inside the foreach you'll see that they are all there.
To store those keys you need to add them to the array, not assign the array. I've corrected the typo $k to $K, and changed aa that goes with f to ff (expecting it to be a typo as well).
my #c;
foreach my $el (#a) {
push #c, sort keys %{$K{$el}};
}
print "#c\n";
This prints the line: ff aa bb. Every time through the loop all keys found in the hash for a particular array element are added to #c, each as a separate element. So #c will contain all bottom-level keys across the whole data structure.
However, there is more that I would like to suggest.
Always use strict; and use warnings; This is not pedantry but it directly helps. I never write code without them. The typo would be caught here, for example.
Use descriptive variable names. Specifically, single-letter variable names are just too easy to confuse, unless in very short loops or where it is crystal clear what they are. (For example, a typo like this couldn't really happen.) Most importantly, the code is going to be far nicer to work with. That generally results in better code.
Please use good indentation and spacing. It helps a lot, in many ways.
A useful core package for nested data structures is Data::Dumper, which can print the whole thing nicely formatted so we can see it. Try to add to the end of your code
use Data::Dumper;
print Dumper(\%K);
There are yet others that do the same or similar.
Here is another way to do what you ask.
my #lowest_keys = map { sort keys %{$K{$_}} } #a;
I call them lowest_keys to emphasize that these are the ones from the last hash in your data structure, the bottom of it. The map applies processing in the block { ... } to each element of #a in turn, returning a list with all these results. (If any one result itself is a list, with more elements than one, it gets merged into the overall output list. So this may create the output list with many more elements than the input.) This list can then be assigned to an array, as above, or passed on to another function that expects a list as input, or interated over.
The map is generally used to transform an array into another, by doing to each element what is in { ... } block. Its close cousin grep is used to filter, so passing through only the elements of the input list for which the condition in { ... } evaluates to true, forming the output list. For example, filter out undefined array elements: my #good = grep { defined } #all
Variable names are case sensitive, so %K... and %k... are not the same.
Always use
use strict;
use warnings;
and declare your variables with my. That prevents you from making this kind of mistakes.
I had got a script in Perl and my task is to do some changes in it. This of course means to understand which part does exactly what. I am not familiar with Perl language but I tried to read through some tutorials, but still some things are confusing me. And I got stuck in following part:
while (<KOEFICIENTYfile>) {
#_=(split(/\s+/, $_));
push(#ZAID,shift(#_));
$KOEFICIENTY{$ZAID[-1]}=[#_];
}
As I understands this part then it:
Reads line from filehandle KOEFICIENTYfile
Separates them by spaces (one or more)
Loads first item from this separated array into array ZAID (and in the process, removes it from #_)
??? Adds a rest of a separated array into array KOEFICIENTY? I am confused by curly brackets part and by square brackets after equals sign.
I think that I understood the meaning of #, $, #_ or negative indexing but this is beyond me. Can you please advice me on meaning of this?
[-1] indexing is just a shortcut way to say "last element of the array".
KOEFICIENTY is actually a hash (you can tell this because it is using curly braces, instead of square ones, around the index), so you're putting the rest of the array #_ into a hash called KOEFICIENTY with a key of the last element of the array.
If you include:
use Data::Dumper
at the top of the script and do
print Dumper(%KOEFICIENTY)
it will nicely format the output for you, which may help
The original coder was trying to be too clever using the negative offset. It would have been much more obvious if the code had been written with a simple temporary variable thus:
while (<KOEFICIENTYfile>) {
#_ = (split(/\s+/, $_));
my $key = shift(#_);
push(#ZAID, $key);
$KOEFICIENTY{$key} = [#_];
}
The braces on $KOEFICIENTY show that this is a "hash" of key/value pairs named %KOEFICIENTY, and not a normal array.
If you don't actually need to preserve the sort order of the keys you could just use keys %KOEFICIENTY to retrieve them instead of storing them in #ZAID.
#zaid is a list, into which the first part of the split is added.
%KOEFICIENTY is a hash, in which a reference to the rest of the split is stored as a list reference under the key of the first part.
So if the line is a b c, #zaid will get a and %KOEFICIENTY{'a'} will hold a reference to a list containing b and c.
I have an array in a perl hash declared like this:
my %updatevars = (datapoints => []);
I'm later trying to add elements to it like this:
push($updatevars{'datapoints'}, [$updatestart+$i, $bandwidth]);
I get this error:
Type of arg 1 to push must be array (not hash element) at dirlist.pl line 61, near "])"
Hashes (and arrays) can only contain scalars. That's why we must put reference to arrays (and hashes) in them. $updatevars{datapoints} contains a reference to an array. As such, you need to use
push #{ $updatevars{datapoints} }, [ $updatestart+$i, $bandwidth ];
Note that your code would work on 5.14+ as push was changed to also accept a reference. (This change is "considered highly experimental" however, so you should use the above code in newer versions too.)
$updatevars{'datapoints'} is an array ref, as you assigned it: []. push takes an array as argument, not an array reference. So you need to dereference your reference:
push #{ $updatevars{'datapoints'} }, ...
In Perl v5.14, you may use a reference, as noted in the documentation. But it does not sound like it is a recommended practice just yet.
Starting with Perl 5.14, "push" can take a scalar EXPR, which must
hold a reference to an unblessed array. The argument will be
dereferenced automatically. This aspect of "push" is considered highly
experimental. The exact behaviour may change in a future version of
Perl.
Try this:
push #{$updatevars{'datapoints'}}, [$updatestart+$i, $bandwidth];
Since push takes an array and $updatevars{'datapoints'} is an array reference, you have to de-reference it by putting the #{} in front.
I have a problem accessing to data, described in the title of the question.
The structure of the data is the following:
my #structure = (
{
"Name" => "Test",
"Param1" => 1,
"Data1" => \#test1,
"Data2" => [\#test3],
"Data3" => [\#test1, \#test2],
},
...
);
And I need to access the 1st (#0) element of the array #test3.
I tried something like this:
my #array = #{$_->{'Data2'}}[0];
print $array[0];
But then I get a reference to the array (ARRAY(0x239c3c)) instead of the required meaning. I feel that there's something global that I don't understand here.
Couldn't you explain how and why I should address to the required meaning?
Thanks a lot.
use strict;
use warnings;
my #test1 = (1,2,3);
my #test2 = (4,5,6);
my #test3 = (7,8,9);
my #structure = (
{
"Name" => "Test",
"Param1" => 1,
"Data1" => \#test1,
"Data2" => [\#test3],
"Data3" => [\#test1, \#test2],
}
);
print $structure[0] # $structure is an array, you want first element...
->{'Data2'} # ...which is a hash reference, you want value for 'Data2'...
->[0] # ...which is holding an array reference to (one element) array #test3...
->[0]; # ...which is an array reference, and you want first element
prints 7.
print $structure[0]{'Data2'}[0][0]; will work!
you just forget the last level!
$_->{'Data2'} is reference to an anonymous array.
#{$_->{'Data2'}}[0] gives you the first element of anonymous array, a reference to another array!
Your code would work if you had "Data2" => \#test3, instead of "Data2" => [\#test3],
You can use the syntactic sugar of -> to get the reference you want. It's much cleaner than using parentheses.
And I need to access the 1st (#0) element of the array #test3
Okay, in your structure, it'd be:
my $element = $structure[0]->{Data2}->[0]->[0];
This is equivalent, but harder to read:
my $element = ${${${$structure[0]}{Data2}}[0]}[0];
And, in this particular case, you can eliminate the syntactic sugar ->:
my $element = $structure[0]{Data2}[0][0];
However, I don't know if that makes it easier to read, and there are cases where the default way of parsing that might not do exactly what you want. I tend to squeeze everything together when I'm referring to an array of arrays, but that's it:
my $element = $array[0][3]; #This is okay
my $element = $array[0]->[3]; #Same as above, but with -> syntax
Otherwise, I'll use the syntactic sweetener of ->.
Here's an explanation of the syntax:
$structure[0] is a reference to the first item of your #structure array. This contains a reference to a hash.
$structure[0]->{Data2} is a reference to the hash element Data2 in the first item in your #structure array. This is a reference to an array.
$structure[0]->{Data2}->[0] is a reference to the first array reference in the Data2 hash element in the first element (0) of your #structure array. This is your #test3 array.
$structure[0]->{Data2}->[0]->[0] is the first element of the #test3 array.
I also recommend you use the Data::Dumper module as you write your code. It'll help you see what structure you're referencing and help point out any errors in the levels. For example:
use Data::Dumper;
print $structure[0]->{Data2}->[0] . "\n";
Will show you that this is a reference to another array layer.
print "$structure[0]\n";
Will show you this is a reference to a hash where each item contains references to arrays of arrays.
Whenever you use these highly complex structures, it screams for using object oriented Perl coding. I'm not 100% sure what you're doing, so I can't help you with your objects, but highly complex structures tend to break and are almost impossible to maintain.
For example, we now do this:
use strict;
use warnings;
my $Foo = "bar";
print "Foo = $foo\n";
This quickly detects that I misspelled my variable name by doing $foo instead of $Foo. This was a big improvement over older versions of Perl where this type of error checking couldn't be done.
However, now look at this:
use strict;
use warnings;
my %hash;
$hash{Foo} = "bar";
print "Foo = $hash{foo}\n";
We've lost the compilation error checking. %hash is a legitimate variable, but $hash{Foo} is defined and not $hash{foo}. In this case, use strict does nothing for you.
Using object oriented Perl returns this error check:
use strict;
use warnings;
use Object::Foo;
my $hash = Object::Foo->new;
$hash->Foo(bar);
print "Foo = " . $hash->foo . "\n";
Whoops! The method should be Foo and not foo. However, Perl is able to detect that the method foo doesn't exist and will once again generate an error on compile.
In the above case, it's pretty straight forward, but you're dealing with an array of hashes of arrays of arrays. The possibility of an error is multiplied by 100 with each reference access. And, because you have to spell out these references over and over in your code, an error can be located in dozens of different places. Even if you could code this initially and then comment the entire structure in your code, it'll be impossible to maintain this when you come back to this after three months.
Take a look at Perldoc's Tutorials and go through the ones for object oriented programming.