Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Hash problem - Perl noob

by UncleTom (Initiate)
on Sep 15, 2006 at 16:45 UTC ( [id://573191]=perlquestion: print w/replies, xml ) Need Help??

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"};

Replies are listed 'Best First'.
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"; }

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
      Thanks for the help. Makes total sense now.
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

      Why
      for (my $i=0;$i<=$#phrase;$i++)
      over the equally efficient yet much more readable
      for my $i (0 .. $#phrase)

        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)

        No good reason ... personal style (or lack thereof), "that's the way I originally learned it", etc. Thanks for reminding me (and the OP) of a better alternative. :)

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
      # or even shorter, but perhaps a bit unreadable: $wordfreq{$_} for (@phrase);

      I think perhaps you meant:

      $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($,,$;,$*,$/)
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.

    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"; }

    Frank Wiles <frank@revsys.com>
    www.revsys.com

      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

        Good catch! Sorry, was hurrying to finish up that post before I had to run out the door.

        Frank Wiles <frank@revsys.com>
        www.revsys.com

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://573191]
Approved by Tanktalus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (None)
    As of 2024-04-25 03:54 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found