Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"

print out the values from a hash

by gibsonca (Beadle)
on Jan 11, 2013 at 17:33 UTC ( #1012932=perlquestion: print w/replies, xml ) Need Help??
gibsonca has asked for the wisdom of the Perl Monks concerning the following question:

I am still struggling a bit with hashes. I want to count the number of strings of the form, "FREQ <val>" in a set of files. I can see that in fact I did count the strings, just not sure how to print the results.

use strict; use warnings; use Env; use integer; use Data::Dumper; my( %cnt, $file, @files, $key, $line, ); @files = <*.abc>; foreach $file (@files) { open (FILE, "$file"); my @contents=<FILE>; close FILE; my @freqs = grep(/ FREQ /,@contents); foreach $line (@freqs) { $line =~ s/ is begin.*//; $line =~ s/.* FREQ/FREQ/; #print "$file $line"; chomp($line); # start counting if (defined $cnt{$line}) { $cnt{$line}{c} = $cnt{$line}{c} + 1; } else { $cnt{$line}{c} = 1; $cnt{$line}{val} = $line; $cnt{$line}{file} = $file; } } # Print out results per file, all the found FREQs: # ( Definitely where I get it wrong starts here ) for $key ( keys %($cnt->{file}) ) { print "key $key \n"; } }

The intended results should be something like the following: FREQ 12.3 5 FREQ 5 2 FREQ 33.3 12

Replies are listed 'Best First'.
Re: print out the values from a hash
by choroba (Bishop) on Jan 11, 2013 at 17:52 UTC
    This is how I would do it. The main changes were:
    • Do not declare variables in a wider scope than needed.
    • Use lexical filehandles and 3-argument open with or die.
    • If you want to output frequencies per file, you have to store them per file. That's why the first key is the filename.
    • The line is already in the key, no need to store it again to a value.
    • You do not have to initialize the counting hash. Just increment it.
    #!/usr/bin/perl use warnings; use strict; my %cnt; for my $file (glob '*.abc') { open my $FILE, '<', "$file" or die "$!"; for my $line (grep / FREQ /, <$FILE>) { $line =~ s/ is begin.*//; $line =~ s/.* FREQ/FREQ/; chomp($line); $cnt{$file}{$line}++; } } for my $file ( keys %cnt) { for my $line ( keys %{ $cnt{$file} } ) { print "$file $line $cnt{$file}{$line}\n"; } }
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: print out the values from a hash
by Kenosis (Priest) on Jan 11, 2013 at 18:11 UTC

    choroba has provided excellent suggestions. Here an option that uses a hash of arrays (HoA), where the key is the file name and its associated value is a reference to a list of frequencies:

    use strict; use warnings; my %files; for my $file (<*.abc>) { open my $fh, '<', $file or die $!; while (<$fh>) { push @{ $files{$file} }, $1 if /FREQ\s+([\d.]+)/; } close $fh; } print "$_ FREQ @{ $files{$_} }\n" for keys %files;

    Output on files containing FREQ <val> info: FREQ 27.047 400 FREQ 33.3 2.22 FREQ 12345.67

    Hope this helps!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1012932]
Front-paged by Arunbear
[Discipulus]: the new spam: gdpr consensus mail
[Corion]: Yeah, but the hope is that when I just delete it I won't receive any more mail from them

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (5)
As of 2018-05-25 07:28 GMT
Find Nodes?
    Voting Booth?