Array of hashes not being passed by ref to sub - perl

I have a setter sub setAssignmentStatus which takes an array of hashes (AoH from here on) and another parameter (do not concern yourself with this as that part works), and does something iterating through the AoH to set another entry in each hash element. It does not return anything because I want to use the same AoH object with the added entries after it is pulled through the setter sub and not construct a whole new AoH and repopulate the entries. Here is the setter:
sub setAssignmentStatus
{
my $fileFlatArySclr = $_[0];
my $cfgFile = $_[1];
#here I convert the AoH from the scalar necessary for the sub to its native form
my #fileFlatAry = #$fileFlatArySclr;
#this works, don't worry
my %cfgVarHash = getConfigVars($cfgFile);
foreach my $fileVarHashSclr(#fileFlatAry)
{
#convert each AoH entry from scalar necessary for iteration to native hash
my %varHash = %$fileVarHashSclr;
my $varName = $varHash{'VAR_NAME'};
my $asgnLineCnt = $varHash{'ASGN_CNT'};
my $asgnSts;
my $fileAsgnSts;
my $cfgAsgnSts;
if($asgnLineCnt > 0) { $fileAsgnSts = 1; } else { $fileAsgnSts = 0; }
my $cfgAsgnLine = $cfgVarHash{$varName};
if($cfgAsgnLine ne undef) { $cfgAsgnSts = 1; } else { $cfgAsgnSts = 0; }
$asgnSts = $fileAsgnSts.$cfgAsgnSts;
#debug to make sure $asgnSts is not null in the first place (it is not!)
print "\n*** setting ASGN_STUS of ".$varName." to ".$asgnSts;
#Here we set ASGN_STUS for every iteration
$varHash{'ASGN_STUS'} = $asgnSts;
}
}
It is called as follows:
setAssignmentStatus(\#fileFlatAry, $cfgFile);
However, after sending the #fileFlatAry AoH through setAssignmentStatus, each element hash does not contain an ASGN_STUS entry. Why is that and how can I fix it?
My suspicion is that I am doing something wrong with the \ modifier, which is how I am getting the data structure to be passed as a scalar parameter to the sub but I am not sure.

You modify %varHash instead of modyfing the referenced hash. Stop copying everything into local variables and modyfying the local variables.
$varHash{'ASGN_STUS'} = ...;
should be
$fileVarHashSclr->{'ASGN_STUS'} = ...;
I wouldn't do my #fileFlatAry = #$fileFlatArySclr; either. Pure waste.

Related

How to dereference entries in a hash of arrays of hashes

I have a data structure that was built like so:-
$ICVDWKey = "($LLX $LLY) ($URX $URY)";
...
push #{$ICVDWStats{$ICVDWKey}}, {
ICVDensity=>$Density,
ICVLayerArea=>$LayerArea,
ICVWindowArea=>$WindowArea
};
I can dereference its contents like so...
foreach $ICVDWKey (#AllICVDWCoords) {
foreach (#{$ICVDWStats{$ICVDWKey}}) {
$ICVDensity = $_->{ICVDensity};
$ICVLayerArea = $_->{ICVLayerArea};
$ICVWindowArea = $_->{ICVWindowArea};
...
}
}
...and everything is good. However, I am running into problems when another data structure is built the same way and I need to check its contents when looping through the original data structure, above. Here is an example...
foreach $ICVDWKey (#AllICVDWCoords) {
foreach (#{$ICVDWStats{$ICVDWKey}}) {
$ICVDensity = $_->{ICVDensity};
$ICVLayerArea = $_->{ICVLayerArea};
$ICVWindowArea = $_->{ICVWindowArea};
...
if (exists ($ICC2DWStats{$ICVDWKey})) {
$ICC2Density = $_->{ICC2Density};
$ICC2LayerArea = $_->{ICC2LayerArea};
$ICC2WindowArea = $_->{ICC2WindowArea};
...
}
}
}
I know the if exists $ICVDWKey matching is working properly, but I cannot cleanly dereference the contents of the ICC2DWStats hash data. What is the proper what to retrieve the ICC2* data when $ICVDWKey keys match between the two data structures? I am sure it is the $_ in the ICC2* references, but I do not know what should be used instead.
Thanks!
Instead of using $_ which represents a structure other than the $ICC2DWStats hashref which you want, you need to explicitly specify the hash and key of the actual hasn you want to extract from:
for $ICVDWKey (#AllICVDWCoords) {
for (#{$ICVDWStats{$ICVDWKey}}) {
$ICVDensity = $_->{ICVDensity};
$ICVLayerArea = $_->{ICVLayerArea};
$ICVWindowArea = $_->{ICVWindowArea};
...
if (exists ($ICC2DWStats{$ICVDWKey})) {
$ICC2Density = $ICC2DWStats->{$ICVDWKey}{ICC2Density};
$ICC2LayerArea = $ICC2DWStats->{$ICVDWKey}{ICC2LayerArea};
$ICC2WindowArea = $ICC2DWStats->{$ICVDWKey}{ICC2WindowArea};
...
}
}
}
Note that you should be using use strict; and use warnings;.

Access an array item in Perl after generating that array

Hello I want to access an specific array item based in a condition previously checked. I leave the code here:
elsif (scalar(#{$boss->bosses}) > 1) {
foreach my $pa (#{$boss->bosses}) {
my $p = My::Model::Group->new(id => $pa->group_id);
push(#$groups, $p);
$valid_pass = 1 if ($pa->checkPassword($self->param('password')));
}
if ($valid_pass) {
my $pa_id = $pa->id;
my $pa_partner_id = $pa->group_id;
}
else {
}
}
What I want to do is, if that if in the array that comes, I check if the password is correct, so if it's correct, then I want to take the id and the group_id of the array item to use it in a function to be able to log them in.
Your for loop is doing two things at once: producing a list of My::Model::Group objects in #$groups, and finding the first boss whose password checks out.
I suggest that you split them up into two clear operations, and the List::Util modules first operator is ideal for the second task
Here's how it would look. I've extracted the result of the method call $boss->bosses into a variable $bosses to avoid repeated calls to the method
Note that you don't need to apply scalar to an array when checking its size. The > and all the other comparators impose scalar context anyway
I've taken much of my code from your question, and I'm a little concerned that you extract values for $pa_id and $pa_partner_id and then just discard them. But I imagine that you know what you really want to do here
use List::Util 'first';
my $bosses = $boss->bosses;
if ( ... ) {
...;
}
elsif ( #$bosses > 1 ) {
#$groups = map { My::Model::Group->new( id => $_->group_id ) } #$bosses;
my $password = $self->param( 'password' );
my $pa = first { $_->checkPassword( $password ) } #$bosses;
if ( $pa ) {
my $pa_id = $pa->id;
my $pa_partner_id = $pa->group_id;
}
else {
...;
}
}

perl cyclic reference. Is this what is happening

I am trying to write a daemon with perl. Now this daemon has the following code
sub b {
my $data;
if (some condition) {
$data->{"endsmeet"} = 1;
} else {
$data->{"endsmeet"} = 2;
}
my $newData = a($data);
}
sub a {
my ($data) = #_;
my %a = ();
my $newData = {
endsmeet => undef,
};
$a{"boo"} = $data->{"endsmeet"};
$newData->{"endsmeet"} = \%a;
return $newData;
}
My question is from the above, does the reference for %a go away and does it get cleaned up when b goes out of scope?
b returns the value of $newdata, which is a reference to an anon hash, which holds a reference to %a, which holds a scalar in the element with key boo.
If the value returned by b not stored, nothing will be referencing the value of $newdata, so it will get freed, so nothing will be referencing the anon hash, so it will get freed, so nothing will reference the scalar in the element with key boo, so it will get freed.
No cycles. No leak.

Can't get values when looping over an array of arrays

I created an array like so:
while(#results = $execute->fetchrow())
{
my $active = 'true';
if($results[1] == 0)
{
$active = 'false';
}
my #campaign = ($results[0], $active);
push(#campaign_names, #campaign);
}
Later, when I need to access the name of the campaign (which is the first element of the campaign array), I can't seem to extract it. What is the proper syntax?
foreach $campaign (#campaign_names)
{
print ????;
}
Thanks!
The problem is you're pushing an array onto the end of #campaign_names, when what you want is an array reference. Here's how I'd write it:
while(#results = $execute->fetchrow())
{
my $active = $results[1] ? 'true' : 'false';
push #campaign_names, [ $results[0], $active ];
}
# later
foreach my $campaign( #campaign_names )
{
my $name = $campaign->[0];
my $active = $campaign->[1];
}
I've cleaned it up a bit by using a ternary conditional (?:) to figure out the value of $active. The [ ... ] constructs an anonymous array reference (a scalar pointing to an array) which is then pushed onto #campaign_names.
When we loop over those later, two important things to notice are that we use my in the loop variable to keep it local to the loop block, and that we use -> to dereference the elements in the array pointed to by the array reference.
That's not creating an array of arrays. my #campaign = ($results[0], $active); push(#campaign_names, #campaign); flattens and pushes $results[0] and $active into the #campaign_names array. Instead, push an arrayref:
my #campaign = ($results[0], $active);
push(#campaign_names, \#campaign);
or
my $campaign = [$results[0], $active];
push(#campaign_names, $campaign);
Arrays can only hold scalar values.
You'll want to refer to perldsc as you learn (perldoc perldsc, http://perldoc.perl.org/perldsc.html)

Shared Hashref of hashes possible?

Im trying to use a hashref of hashes to store a persistant field and a timestamp of when that field was changed.
It needs to be shared though as I have 2 threads that are required to access it although only one sets the values.
here is my current code with several commented out variations:
my $status = {};
share($status);
sub get_status {
my($raid) = #_;
return $status->{$raid}->{status} if exists $status->{$raid};
return 1;
}
sub set_status {
my($raid,$newstatus) = #_;
my %t;
$t{status} = $newstatus;
$t{timestamp} = Time::HiRes::time;
$status->{$raid} = \%t;
#$status->{$raid} = {
#status => $newstatus,
#timestamp => Time::HiRes::time()
#};
#$status->{$raid}->{status}=$newstatus;
#$status->{$raid}->{timestamp} = Time::HiRes::time;
return 1;
}
set_status('680','1');
get_status('680');
I continually get Invalid value for shared scalar at ./hashtest line 19.
Could anyone help please :D?
This perlmonks page should explain the problem. One of the posts claims:
You can share nested hash, as long as the internal hashes are also marked as shared.
You can try something like this:
share( %t );
$status->{ $raid } = \%t;