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.
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'm trying to create a sparse array in Swift. I'm not sure if the problem is in my declaration (no syntax errors detected) or possibly a bug in beta 2?
I am trying to declare an array of 24 class instances as optionals. I then can fill in slots of the array as necessary. Here is the declaration:
var usage = WaterUsage?[](count:24, repeatedValue:nil)
This gets through the Xcode 6 beta 2 compiler without error. The intention is to end up with an array of 24 "WaterUsage" classes all set to nil.
When I try to set an array element:
usage[hour] = usage
where hour is < 24 I get the error:
"WaterUsage doesn't have a member named subscript"
I've also tried using generics but that doesn't appear to work either.
I find the Swift syntax for using optionals in complex data structures is a little obscure and could use some advice here.
That way of defining the array is giving you an Optional array of Optional values ( WaterUsage?[]? ), which you have to unwrap before you can use. I think you want just the values to be optional: WaterUsage?[]. One way I've been able to do that is by using the generic Array syntax:
var usage: WaterUsage?[] = Array<WaterUsage?>(count:24, repeatedValue:nil)
usage[hour] = something
Another way is to force unwrapping of the return value of your initial declaration. I don't know why, but WaterUsage?[]() has an Optional return value.
var usage = (WaterUsage?[](count:24, repeatedValue:nil))!
usage[hour] = something
You're pretty close! When using the MemberType[] syntactic sugar for arrays, the way that you wrote it (WaterUsage?[]) actually declares the Array as Optional, as well as the values that it holds. In which case, to assign a value to an index you would need to unwrap the Array first by using:
usage![hour] = someWaterUsage
However, if you only want Optional members in the Array (and don't want the Array itself to be optional), then you can fall back to the standard Array declaration:
var usage = Array<WaterUsage?>(count:24, repeatedValue:nil)
edit:
I originally offered an alternate syntax as another solution as well:
var usage = (WaterUsage?)[](count:24, repeatedValue:nil)
...but in doing so, per #Nate's observations it then becomes the case that you need to use unwrapping twice to access the value at a specific index, for example:
usage[0]!!.someProperty
this is just a shot in the dark, but I think what may be happening in this case is not dissimilar at all to what OP originally tried with declaring the Array using WaterUsage?[]
that is, when using (WaterUsage?)[], perhaps it is seeing this declaration as an Array of Optional Tuples holding Optional WaterUsages, requiring us then to unwrap the member at the index twice before we can access its properties
interesting stuff!
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.
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};