in reply to Re: Re: counting occurances
in thread counting occurances
my $header_line = <DATA>; my %count; my @chars = ( qw/F G S/ ); while (my $line = <DATA> ) { eval "\$count{$_} += \$line =~ tr/$_/$_/,1" or die $@ foreach @chars; } print "There are $count{$_} occurrences of $_\n" foreach sort keys %count; __DATA__ Sample header hine FDIELSIGCOXLSAGICK\n FDIELSIGCOXLSAGICK\n
The reason that the tr/// must appear inside of an eval block is that variables are not interpolated in tr/// (the transliteration table is built at compiletime, not runtime). Eval forces a fresh compilation of tr/// each time through the loop.
The reason that I pass references is because I want the variables to exist as variables inside the eval, not as values (except in the case of what's inside the tr/// itself).
And the '1' appears at the end of the eval expression so that eval returns safely (without croaking) even if no matches are found.
I think this is an elegant solution, and saves a lot of intricate fiddling.
If you want to see a solution that uses index instead of tr///, you may...
Just to see what it would look like I also did it with index instead of a regexp or tr/// counting mechanism. The index method took three loops, and I don't really like it that much, but it works, and has the advantage of also working if you are looking for whole words instead of just individual letters. Here it is.
use strict; use warnings; my $header_line = <DATA>; my %count; my @chars = ( qw/F G S/ ); while ( my $line = <DATA> ) { foreach ( @chars ) { my $pos = 0; while ( ($pos = index( $line, $_, $pos ) ) >= 0) { $count{$_}++; $pos++; } } } print "There are $count{$_} occurrences of $_\n" foreach sort keys %count; __DATA__ Sample header hine FDIELSIGCOXLSAGICK\n FDIELSIGCOXLSAGICK\n
I still prefer the flow of the tr/// or m//g methods, but index definately gets the job done without mucking things up too badly.
Dave
"If I had my life to do over again, I'd be a plumber." -- Albert Einstein
|
|---|