JusaEngineer has asked for the wisdom of the Perl Monks concerning the following question:

Any help would be greatly appreciated,
Here is an example hash of the same format I'm using. I've been trying the past three days to figure out how to count the times that "ScreenName" equals "A".

I need something like:
A - 3
B - 2


I would also like to know how I could make a new hash out of this one that has "ScreenName" as the $key and "Description" . " " . "Type" as the elements.

use warnings; use strict; use Data::Dumper; my %hash = ( 'ScreenName1.Description1' => { 'ScreenName' => 'A', 'Description' => 'A Description of this button', 'Type' => 'On/Off' }, 'ScreenName2.Description2' => { 'ScreenName' => 'B', 'Description' => 'A Description of this button', 'Type' => 'Momentary' }, 'ScreenName3.Description3' => { 'ScreenName' => 'A', 'Description' => 'A Description of this button', 'Type' => 'Momentary' }, 'ScreenName4.Description4' => { 'ScreenName' => 'A', 'Description' => 'A Description of this button', 'Type' => 'On/Off' }, 'ScreenName5.Description5' => { 'ScreenName' => 'B', 'Description' => 'A Description of this button', 'Type' => 'On/Off' }, ); print Dumper(%hash);

The closest I've gotten so far is something similar to what's below but I can't see to figure out how to compare the actual $hash{$tag}{'ScreenName'} The commented out section is some things I was trying that didn't work.

for $key (sort keys %hashc) { print "$key: \n"; for $ele (keys %{$hash{$key}}) { # my $p=0; # #if ($ele{'ScreenName'} =~ /A/){ # $p++; # } else { # #print "\n $ele{'ScreenName'} --- $p \n"; # $p=0; # } print " $ele: \t\t" . $hash{$key}->{$ele} . "\n"; } }

Thank you, Mel

Replies are listed 'Best First'.
Re: counting occurrence of an element in a hash
by davido (Cardinal) on Jun 05, 2021 at 00:51 UTC

    It's actually easier than you're making it:

    use warnings; use strict; use Data::Dumper; my %hash = ( 'ScreenName1.Description1' => { 'ScreenName' => 'A', 'Description' => 'A Description of this button', 'Type' => 'On/Off' }, 'ScreenName2.Description2' => { 'ScreenName' => 'B', 'Description' => 'A Description of this button', 'Type' => 'Momentary' }, 'ScreenName3.Description3' => { 'ScreenName' => 'A', 'Description' => 'A Description of this button', 'Type' => 'Momentary' }, 'ScreenName4.Description4' => { 'ScreenName' => 'A', 'Description' => 'A Description of this button', 'Type' => 'On/Off' }, 'ScreenName5.Description5' => { 'ScreenName' => 'B', 'Description' => 'A Description of this button', 'Type' => 'On/Off' }, ); my %ScreenNameCount; $ScreenNameCount{$hash{$_}{ScreenName}}++ foreach keys %hash; print Dumper \%ScreenNameCount;

    This outputs:

    $VAR1 = { 'A' => 3, 'B' => 2 };

    Dave

      Thank you very much this is what I was trying to accomplish but couldn't get to the sub element.
Re: counting occurrence of an element in a hash
by kcott (Archbishop) on Jun 05, 2021 at 04:02 UTC

    G'day JusaEngineer,

    Welcome to the Monastery.

    You can collate all the information you want in a single, new hash by iterating the values of %hash and transferring information to the new hash.

    In the script below, I've given all of the Descriptions unique values: you can now tell all three "A Description of this button On/Off" apart (ditto for the two with "Momentary").

    #!/usr/bin/env perl use strict; use warnings; my %hash = ( 'ScreenName1.Description1' => { 'ScreenName' => 'A', 'Description' => 'Desc1', 'Type' => 'On/Off' }, 'ScreenName2.Description2' => { 'ScreenName' => 'B', 'Description' => 'Desc2', 'Type' => 'Momentary' }, 'ScreenName3.Description3' => { 'ScreenName' => 'A', 'Description' => 'Desc3', 'Type' => 'Momentary' }, 'ScreenName4.Description4' => { 'ScreenName' => 'A', 'Description' => 'Desc4', 'Type' => 'On/Off' }, 'ScreenName5.Description5' => { 'ScreenName' => 'B', 'Description' => 'Desc5', 'Type' => 'On/Off' }, ); my %parsed; for (values %hash) { push @{$parsed{$_->{ScreenName}}}, join ' ', @{$_}{qw{Description Type}}; } print "*** Counts ***\n"; print "$_ - ", 0+@{$parsed{$_}}, "\n" for keys %parsed; print "\n*** New hash (\%parsed) ***\n"; use Data::Dump; dd \%parsed;

    Output from a sample run:

    *** Counts *** A - 3 B - 2 *** New hash (%parsed) *** { A => ["Desc1 On/Off", "Desc3 Momentary", "Desc4 On/Off"], B => ["Desc2 Momentary", "Desc5 On/Off"], }

    Note that hashes are unordered. Here's the output from another sample run:

    *** Counts *** B - 2 A - 3 *** New hash (%parsed) *** { A => ["Desc3 Momentary", "Desc1 On/Off", "Desc4 On/Off"], B => ["Desc5 On/Off", "Desc2 Momentary"], }

    Depending on how you want to use the data, you may need to use sort in one of more places. For future reference, please note that if you specify requirements you'll generally get better answers: all I have to work with is "something like" for part one, and no information at all for part two.

    See also: Data::Dump.

    — Ken

      Thank you for your answer, It was helpful!

Re: counting occurrence of an element in a hash (updated)
by AnomalousMonk (Archbishop) on Jun 05, 2021 at 01:44 UTC
    I would also like to know how I could make a new hash out of this one that has [? the value of ?] "ScreenName" as the $key and "Description" . " " . "Type" as the elements.

    I don't quite understand what you mean by this (you provide no expected output structure as an example (update: see also How to ask better questions using Test::More and sample data)), but here's a guess:

    Win8 Strawberry 5.8.9.5 (32) Fri 06/04/2021 21:34:07 C:\@Work\Perl\monks >perl use strict; use warnings; use Data::Dumper; my %hash = ( 'ScreenName1.Description1' => { 'ScreenName' => 'A', 'Description' => 'A Description of this button', 'Type' => 'On/Off' }, 'ScreenName2.Description2' => { 'ScreenName' => 'B', 'Description' => 'A Description of this button', 'Type' => 'Momentary' }, 'ScreenName3.Description3' => { 'ScreenName' => 'A', 'Description' => 'A Description of this button', 'Type' => 'Momentary' }, 'ScreenName4.Description4' => { 'ScreenName' => 'A', 'Description' => 'A Description of this button', 'Type' => 'On/Off' }, 'ScreenName5.Description5' => { 'ScreenName' => 'B', 'Description' => 'A Description of this button', 'Type' => 'On/Off' }, ); my %ScreenNameValues; for my $hr (values %hash) { $ScreenNameValues{ $hr->{'ScreenName'} }++; } print Dumper \%ScreenNameValues; print "$_ == $ScreenNameValues{$_} \n" for sort keys %ScreenNameValues +; my %ScreenNameDT; for my $hr (values %hash) { push @{ $ScreenNameDT{ $hr->{'ScreenName'} } }, "$hr->{'Description'} $hr->{'Type'}"; } print Dumper \%ScreenNameDT; ^Z $VAR1 = { 'A' => 3, 'B' => 2 }; A == 3 B == 2 $VAR1 = { 'A' => [ 'A Description of this button Momentary', 'A Description of this button On/Off', 'A Description of this button On/Off' ], 'B' => [ 'A Description of this button Momentary', 'A Description of this button On/Off' ] };

    Update: Also see also Perl Data Structures Cookbook.


    Give a man a fish:  <%-{-{-{-<

      Thank you for the CookBook Link, I found it very Helpful in understanding how the structures work.
      I have made a new post trying to solve this problem and I tried to be as descriptive as possible. Thank you.