Perl Monk, Perl Meditation PerlMonks

### Re: Hash Manipulation

by haukex (Bishop)
 on Jun 08, 2021 at 07:20 UTC Need Help??

The main issue with the code you've shown is that in the three places you're doing something like $HashCount{$Screenkey} = {$i => "..."}, you're replacing what's stored in$HashCount{$Screenkey} with a new reference to a new anonymous hash, instead of adding something to the existing hash. You can delete the line$HashCount{$Screenkey} =$Screenkey; since that value is going to get replaced anyway. Then, you can replace the three aforementioned hash accesses with $HashCount{$Screenkey}{0} and $HashCount{$Screenkey}{$i} respectively - what this does is take advantage of a Perl feature called autovivification, which means that simply accessing$HashCount{$Screenkey} as if it were a reference to a hash causes a new anonymous hash to be created for you. I think you've also got a logic issue with$i - in the case that $Screenkey ne$ScreenkeyOld, I am guessing that you probably want to start the numbering over - but you're only resetting $i=1 after already having used its previous value. The same goes for$i++. If I fix this, the next issue is that I think you've got a mistake in your sample data: since you're iterating over the sorted keys of %hash, Alarms will come first, but in your sample data you seem to expect the order to be Trend to USB, Alarms, and Flow Diagram. I haven't fixed this issue in the code below.

In general, note that you have two unused variables, @List and the outer $Screenkey, since you're only using the second$Screenkey defined inside the loop. Also, your code would benefit from better indentation - perltidy can help with that. And you can do away with %ScreenNameCount, since you can do that operation directly in %HashCount.

Putting all of that together (as mentioned above the test will fail since I haven't changed the order of the expected output you showed in your question):

use warnings;
use strict;

my %hash = (
'Alarms.Alarm Acknowledge' => {
'ScreenName'  => 'Alarms',
'Description' => 'Alarm Acknowledge',
'Type'        => 'On/Off',
},
'Flow Diagram.Sequence Hold' => {
'ScreenName'  => 'Flow Diagram',
'Description' => 'Sequence Hold',
'Type'        => 'Momentary',
},
'ScreenName'  => 'Flow Diagram',
'Type'        => 'Momentary',
},
'Flow Diagram.Sanitize Enable/Disable' => {
'ScreenName'  => 'Flow Diagram',
'Description' => 'Sanitize Enable/Disable',
'Type'        => 'On/Off',
},
'Trend to USB.Start/Stop Trend Toggle' => {
'ScreenName'  => 'Trend to USB',
'Description' => 'Start/Stop Trend Toggle',
'Type'        => 'On/Off',
},
'Alarms.Alarm Reset' => {
'ScreenName'  => 'Alarms',
'Description' => 'Alarm Reset',
'Type'        => 'On/Off',
},
'Alarms.Alarm Trigger' => {
'ScreenName'  => 'Alarms',
'Description' => 'Alarm Trigger',
'Type'        => 'Momentary',
},
);

my %HashCount;
$HashCount{$hash{$_}{ScreenName} }{0}++ foreach keys %hash; my$ScreenkeyOld = 'Old';
my $i = 1; foreach my$key ( sort keys %hash ) {
my $Screenkey =$hash{$key}{ScreenName}; my$Description = $hash{$key}{Description};
my $Type =$hash{$key}{Type}; if ($Screenkey eq $ScreenkeyOld ) {$i++;
#print "$Screenkey <$i>\n"; #Debug
$HashCount{$Screenkey}{$i} = "\\t \\t \\t \\t\& \\mytabhead{$D
+escription} \\t\& $Type \\t\\\\ \\hline \\n$i - $Screenkey -$Screen
+keyOld";
}
else {
$i = 1; #print "$ScreenkeyOld -> $Screenkey <$i>\n"; #Debug
$HashCount{$Screenkey}{$i} = "\\mytabhead{$Screenkey} \\t\& \\
+mytabhead{$Description} \\t\&$Type \\t\\\\ \\hline \\n $i -$Screenk
+ey - $ScreenkeyOld"; }$ScreenkeyOld = $Screenkey; } use Test::More tests=>1; is_deeply \%HashCount, { 'Alarms' => { '0' => 3, '1' => '\\mytabhead{Alarms} \\t& \\mytabhead{Alarm Trigger} \ +\t& Momentary \\t\\\\ \\hline \\n 1 - Alarms - Trend to USB', '2' => '\\t \\t \\t \\t& \\mytabhead{Alarm Acknowledge} \\t& O +n/Off \\t\\\\ \\hline \\n 2 - Alarms - Alarms', '3' => '\\t \\t \\t \\t& \\mytabhead{Alarm Reset} \\t& On/Off +\\t\\\\ \\hline \\n 3 - Alarms - Alarms', }, 'Flow Diagram' => { '0' => 3, '1' => '\\mytabhead{Flow Diagram} \\t& \\mytabhead{Sequence A +dvance} \\t& Momentary \\t\\\\ \\hline \\n 1 - Flow Diagram - Alarms' +, '2' => '\\t \\t \\t \\t& \\mytabhead{Sequence Hold} \\t& Momen +tary \\t\\\\ \\hline \\n 2 - Flow Diagram - Flow Diagram', '3' => '\\t \\t \\t \\t& \\mytabhead{Sanitize Enable/Disable} +\\t& On/Off \\t\\\\ \\hline \\n 3 - Flow Diagram - Flow Diagram', }, 'Trend to USB' => { '0' => 1, '1' => '\\mytabhead{Trend to USB} \\t& \\mytabhead{Start/Stop +Trend Toggle} \\t& On/Off \\t\\\\ \\hline \\n 1 - Trend to USB - Old' +, }, } or diag explain \%HashCount; [download] Replies are listed 'Best First'. Re^2: Hash Manipulation by JusaEngineer (Novice) on Jun 08, 2021 at 13:53 UTC Thank you for your insight. You have solved some of my issues and moved me along. I'm getting the data in the format I would like it. I am able to print the screens with the correct number of buttons in the "\multirow{??}". The only issue I have now that is keeping me from completing this is, counting down buttons available per page and then formatting the changes to "\multirow{??}" as it is effected by being split between pages. Sorry about the order of the sorted elements, I wasn't thinking about it when I was typing up the sample result. I was trying to make sure that a$key was page broken.

This is what I have now. I think that if I manipulate a few more if statements I can count down remaining buttons and check that each time that $ele = 0, to determine if I need to split it and update the "\multirow{??}". I may need to count down buttons per screen remaining also. my$MaxButtons = 5;
my $RemainingButtons =$MaxButtons;
my $ButtonsOnPage = 0; for$key (sort keys %HashCount)
{
for $ele (sort keys %{$HashCount{$key}}) { if ($ele eq 0){
} else {
if ($ele eq 1){ print "\\multirow{$HashCount{$key}->{0}}{0.85in}{\\myt +abhead{$key}} \& " . $HashCount{$key}->{$ele} . "\n"; } else { print " \& " .$HashCount{$key}->{$ele} . "\n";
}

}
}
}
[download]

In your code you have this block (I've shortened the print statements for clarity):

        if ($ele eq 0){ } else { if ($ele eq 1){
print "Condition: ele is 1\n";
} else {
print "Condition: ele is neither 1 nor 0\n";
}

}
[download]

This is confusing because of the empty block straddling the first 2 lines. There are a couple of ways to avoid it in general. One is to negate the condition:

        if ($ele ne 0){ if ($ele eq 1){
print "Condition: ele is 1\n";
} else {
print "Condition: ele is neither 1 nor 0\n";
}

}
[download]

The other is to turn the if into an unless:

        unless ($ele eq 0){ if ($ele eq 1){
print "Condition: ele is 1\n";
} else {
print "Condition: ele is neither 1 nor 0\n";
}

}
[download]

Either of these removes the empty block, so that's a plus. But we can go farther. The logic can be simplified because really you have only 2 conditions as indicated by my rewritten print statements. So we can remove the outer condition by folding it into the else like so:

            if ($ele eq 1){ print "Condition: ele is 1\n"; } elsif ($ele ne 0) {
print "Condition: ele is neither 1 nor 0\n";
}
[download]

Finally, deducing from your previous code that $ele is only ever a whole number you can switch to using numerical comparisons rather than string comparisons (== instead of eq, etc.). Perhaps this is the clearest:  if ($ele == 1) {
print "Condition: ele is 1\n";
} elsif (\$ele > 1) {
print "Condition: ele is neither 1 nor 0\n";
}
[download]

I understand that you are just hacking about with this code but wanted to point out these alternative ways of going about the logical if-blocks. The simpler you can make it the fewer bugs can creep in and that has to be a good thing.

🦛

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11133647]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (3)
As of 2021-07-31 22:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?

No recent polls found

Notices?