Problems? Is your data what you think it is? 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);
[download]```

and the string:

```\$string = "AFTYUBEWTWECRTUTYIYTDDDDRYJURTHJTREEEEEFGSDFF";
[download]```

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;
}
[download]```

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...

Code tags added by GrandFather

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;
[download]```

Prints:

```A = 1
B = 1
C = 1
D = 5
E = 7
F = 4
[download]```

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
[download]```

Prasad

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";
}
[download]```
You can also use a substitution in order to interpolate but avoid the eval.
```\$count = \$string =~ s/\$a//g;
[download]```
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);
[download]```
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";
[download]```

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
[download]```
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)
[download]```
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)
[download]```
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... :(

Log In?
 Username: Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://526711]
Approved by Corion
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (9)
As of 2018-01-16 14:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
How did you see in the new year?

Results (180 votes). Check out past polls.

Notices?