UncleTom has asked for the wisdom of the Perl Monks concerning the following question:
I am just starting out with Perl and I am reading the 6-part tutorial on perl.com. I am working on their first exercise which is a word frequency counter and I am stuck. I'm reading the array or words into a hash and the hash values seem to be correct but I am having trouble formatting the report. Thanks in advance for any help.
use strict;
use warnings;
my(@phrase) = ("apple", "apple", "banana", "banana", "pear", "pear", "
+pear", "kiwi", "kiwi");
my($i) = 0;
my($j) = 0;
my(%wordfreq) = ();
for $i (@phrase) {
$wordfreq{"$phrase[ $j ]"}++;
# print "$wordfreq{\"$phrase[ $j ]\"} appears $wordfreq{\"$phrase[
+$j ]\"}\n";
$j++;
}
print keys %wordfreq;
print $wordfreq{"apple"};
print $wordfreq{"banana"};
print $wordfreq{"pear"};
print $wordfreq{"kiwi"};
Re: Hash problem - Perl noob
by japhy (Canon) on Sep 15, 2006 at 16:54 UTC
|
Here's a bit of critique...
for $i (@phrase) {
$wordfreq{"$phrase[ $j ]"}++;
# print "$wordfreq{\"$phrase[ $j ]\"} appears $wordfreq{\"$phrase[
+$j ]\"}\n";
$j++;
}
First, in each run of the loop over @phrase, $i holds the particular element, so you can be saying $wordfreq{$i}++ instead of $wordfreq{$phrase[$j]}. Second, you're using quotes around $phrase[$j] that are totally unnecessary. Third, your (commented out) print statement probably should have looked like: print "$i appears $wordfreq{$i} times\n";.
As for your "trouble formatting the report", maybe you should print some newlines or something.
for my $word (keys %wordfreq) {
print "$word appears $wordfreq{$word} times\n";
}
| [reply] [d/l] [select] |
|
Thanks for the help. Makes total sense now.
| [reply] |
Re: Hash problem - Perl noob
by ptum (Priest) on Sep 15, 2006 at 16:55 UTC
|
You seem to be stepping through the contents of @phrase with an i-based for loop, yet you're referring to the jth element in @phrase. You need to make up your mind ... are you iterating through @phrase with i or with j?
I think either of these (untested) would do what you want:
foreach (@phrase) {
$wordfreq{$_}++;
}
or this:
for (my $i=0;$i<=$#phrase;$i++) {
$wordfreq{$phrase[$i]}++;
}
No good deed goes unpunished. -- (attributed to) Oscar Wilde
| [reply] [d/l] [select] |
|
| [reply] [d/l] [select] |
|
over the equally efficient ...
i think a "foreach loop" is more efficient, but maybe i'm making a mistake in my benchmark?
perl -wle'
use Benchmark;
my $max = $ARGV[0];
timethese($ARGV[1]||-1, {
for => sub { for (my $i=0;$i<$max;$i++) { 1 } },
foreach => sub { for my $i (0..$max-1) { 1 } },
}
)' 10000 2000
Benchmark:
timing 2000 iterations of
for, foreach
...
for: 8 wallclock secs ( 7.63 usr + 0.00 sys = 7.63 CPU) @ 26
+2.12/s (n=2000)
foreach: 5 wallclock secs ( 5.38 usr + 0.00 sys = 5.38 CPU) @ 37
+1.75/s (n=2000)
| [reply] [d/l] |
|
|
| [reply] |
Re: Hash problem - Perl noob
by rminner (Chaplain) on Sep 15, 2006 at 17:03 UTC
|
Hi,
when using for $i (@phrase), the variable $i becomes an alias for all the elements in the list @phrase. In the first run it contains "apple", then "apple" , then "banana" , etc..
If you have this construct, you don't need the additional counter $j. A bit shorter would be:
for my $elem (@phrase) {
$wordfreq{$elem}++;
}
# or even shorter, but perhaps a bit unreadable:
$wordfreq{$_} for (@phrase);
Update: Thanks to chargrill for pointing out my typo, indeed it should be:
$wordfreq{$_}++ for (@phrase);
When printing out the results you might want to print out the name of what you found, for example:
foreach my $key (sort keys %wordfreq) {
print "$key: $wordfreq{$key}\n";
}
Hope this was the answer you were looking for.
Cheers
Roland | [reply] [d/l] [select] |
|
$wordfreq{$_}++ for (@phrase);
Since, after all, it's supposed to count the frequency of each word :)
--chargrill
s**lil*; $*=join'',sort split q**; s;.*;grr; &&s+(.(.)).+$2$1+; $; =
qq-$_-;s,.*,ahc,;$,.=chop for split q,,,reverse;print for($,,$;,$*,$/)
| [reply] [d/l] [select] |
Re: Hash problem - Perl noob
by Tanktalus (Canon) on Sep 15, 2006 at 16:49 UTC
|
Ok, so what are you trying to get it to do? What we have here is what you have tried, and the concept that "it didn't work." What we're missing is what you're expecting it to do and/or what you're hoping to get it to do.
| [reply] |
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: Hash problem - Perl noob
by ides (Deacon) on Sep 15, 2006 at 16:57 UTC
|
First off you don't need to put parens around your variables. And what is going wrong is you're trying to look up values from @phrase, when you don't need to. Here is how I would write this, following your style:
use strict;
use warnings;
my @phrase = ( 'apple', 'apple', 'banana', 'banana', pear', 'pear',
'kiwi', 'kiwi' );
my %wordfreq;
# Here $i contains the actual value from @phrase
foreach my $i ( @phrase ) {
$wordfreq{$i}++;
print "$i appears ", $wordfreq{$i}, "\n";
}
| [reply] [d/l] |
|
Did you really mean to put your print statement in the foreach my $i ( @phrase ) { ... } loop? I think you are going to get eight lines of running total information like
apple appears 1
apple appears 2
banana appears 1
banana appears 2
pear appears 1
pear appears 2
kiwi appears 1
kiwi appears 2
rather than a summary of the word frequencies. To get a summary you could do something like
print qq{$_ appears $wordfreq{$_} times\n}
for sort keys %wordfreq;
after the foreach loop. Cheers, JohnGG | [reply] [d/l] [select] |
|
| [reply] |
|
|