There's more than one way to do things PerlMonks

### This should be easy: counting letters in a string

 on Jan 31, 2006 at 11:23 UTC Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi all!

My question is rather silly, but I can't seem to be able to find the solution myself...

I have the array:

@letters = (A,B,C,D,E,F);

and the string:

\$string = "AFTYUBEWTWECRTUTYIYTDDDDRYJURTHJTREEEEEFGSDFF";

and I want to find how many times each letter appears in the \$string.

I go like:

foreach \$a(@letters) { \$count = (\$string = ~tr/\$a//); print \$count; }

But it doesn't count anything...

Does it have to do with the \$a in the pattern matching?

I tested the same thing and instead of \$a I put A or B etc and it works...

2006-01-31 Retitled by g0n, as per Monastery guidelines
Original title: 'This should be easy...'

Replies are listed 'Best First'.
Re: This should be easy: counting letters in a string
by GrandFather (Sage) on Jan 31, 2006 at 11:56 UTC

Another way to do it:

use strict; use warnings; my @letters = qw(A B C D E F); my \$string = "AFTYUBEWTWECRTUTYIYTDDDDRYJURTHJTREEEEEFGSDFF"; my %chCount; ++\$chCount{\$_} for split '', \$string; print "\$_ = \$chCount{\$_}\n" for @letters;

Prints:

A = 1 B = 1 C = 1 D = 5 E = 7 F = 4

DWIM is Perl's answer to Gödel
Re: This should be easy: counting letters in a string
by prasadbabu (Prior) on Jan 31, 2006 at 11:44 UTC

As inman suggested you can make use of eval. If you dont have any peroformance issue, you can use s operator.

@letters = qw(A B C D E F); \$string = "AFTYUBEWTWECRTUTYIYTDDDDRYJURTHJTREEEEEFGSDFF"; for \$a (@letters) { \$count = \$string =~ s/\$a//g; print "\$count\n"; } output: 1 1 1 5 7 4

Re: This should be easy: counting letters in a string
by inman (Curate) on Jan 31, 2006 at 11:36 UTC
The transliteration does not interpolate the variable as you expect in your sample. The following illustrates the use of eval.
use strict; use warnings; my @letters = qw (A B C D E F); my \$string = "AFTYUBEWTWECRTUTYIYTDDDDRYJURTHJTREEEEEFGSDFF"; my \$count; foreach my \$a(@letters) { eval "\\$count = \\$string =~ tr/\$a//"; print "\$count\n"; }
You can also use a substitution in order to interpolate but avoid the eval.
\$count = \$string =~ s/\$a//g;
Both methods change the string. A more flexible way to count the values would be to split the string and use a hash to store the values.
my %count; \$count{\$_}++ foreach split //, \$string; print "\$count{\$_}\n" foreach (@letters);
Both methods change the string.
No, tr/a// will not delete characters unless you specify the d modifier. Characters that are not replaced are left alone.

And using a little trick to induce list context, you can use pattern matching to count the occurrences:

my @letters = qw(A B C D E F); my \$string = 'AFTYUBEWTWECRTUTYIYTDDDDRYJURTHJTREEEEEFGSDFF'; my @counts; for (0..\$#letters) { \$counts[\$_] = () = \$string =~ /\$letters[\$_]/g; } print "@counts\n";

Caution: Contents may have been coded under pressure.
Re: This should be easy: counting letters in a string
by gube (Parson) on Jan 31, 2006 at 12:01 UTC
map { print \$count = \$string =~ s/\$_//g } @letters;
Re: This should be easy: counting letters in a string
by myuji (Acolyte) on Jan 31, 2006 at 12:48 UTC
I thought of this way:
my @letters = qw (A B C D E F); my \$string = "AFTYUBEWTWECRTUTYIYTDDDDRYJURTHJTREEEEEFGSDFF"; foreach (@letters) { my \$count = 0; \$count ++ while \$string =~ /\$_/g; print "\$_ : \$count\n"; } output: A : 1 B : 1 C : 1 D : 5 E : 7 F : 4
But, it looks like the way using 'm//g' is slower than 's///g'. Benchmark:
use Benchmark; my @letters = qw (A B C D E F); my \$string = "AFTYUBEWTWECRTUTYIYTDDDDRYJURTHJTREEEEEFGSDFF" x 100; timethese(1000,{ match=>\&match,subst=>\&subst}); sub match{ my \$str = \$string; foreach (@letters) { my \$count = 0; \$count ++ while \$str =~ /\$_/g; # print "\$_ : \$count\n"; } } sub subst{ my \$str = \$string; foreach (@letters){ my \$count = \$str =~ s/\$_//g; # print "\$_ : \$count\n"; } } output: Benchmark: timing 1000 iterations of match, subst... match: 10 wallclock secs ( 2.52 usr + 0.01 sys = 2.53 CPU) @ 39 +5.26/s (n=1000) subst: 2 wallclock secs ( 1.88 usr + 0.01 sys = 1.89 CPU) @ 52 +9.10/s (n=1000)
Hope this helps,
Re: This should be easy: counting letters in a string
by McDarren (Abbot) on Jan 31, 2006 at 14:21 UTC
Nobody else seems to have pointed this out, so I will..
foreach \$a(@letters)
Although I realise this is just a short code snippet, the use of \$a as a variable name is a bad habit(tm) to get into. Both \$a and \$b are package globals which are used by sort. If you get into the habit of using them elsewhere, this habit will eventually come back and bite you on the rear end ;)

Cheers,
Darren :)

Re: This should be easy: counting letters in a string
by Anonymous Monk on Jan 31, 2006 at 13:10 UTC
Thanx to all of you.... I am so angry with myself for not being able to solve such an easy task.. And, by judging from the vast amount of answers I got, I must have been soooooooo easy... :(

Create A New User
Node Status?
node history
Node Type: perlquestion [id://526711]
Approved by Corion
help
Chatterbox?
 [Corion]: Hmm. My overkill logging of transactions seems to bear fruit. I've built it in a way that the decision on every transaction must be logged, even if the transaction is just skipped, to prevent silent skips. [Corion]: Now, three years in production, it found a situation (during development) where stuff was skipped without getting a log message.

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2017-08-21 07:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Who is your favorite scientist and why?

Results (318 votes). Check out past polls.

Notices?