Here's one way to do it:
my %last_name = qw{
fred flintstone
barney rubble
wilma flintstone
};
print "Please enter a first name: ";
chomp(my $name = <STDIN>);
print "That's $name $last_name{$name}.\n";
In this one, we used a qw// list (with curly
braces as the delimiter) to initialize the hash. That's fine
for this simple data set, and it's easy to maintain because
each data item is a simple given name and simple family name, with
nothing tricky. But if your data might contain spaces -- for
example, if robert de niro or
mary kay place were to visit Bedrock -- this
simple method wouldn't work so well.
You might have chosen to assign each key/value pair separately,
something like this:
my %last_name;
$last_name{"fred"} = "flintstone";
$last_name{"barney"} = "rubble";
$last_name{"wilma"} = "flintstone";
Note that (if you chose to declare the hash with
my, perhaps because use
strict was in effect), you must declare the hash
before assigning any elements. You can't use
my on only part of a variable, like this:
my $last_name{"fred"} = "flintstone"; # Oops!
The my operator works only with
entire variables, never with just one element of
an array or hash. Speaking of lexical variables, you may have noticed
that the lexical variable $name is being declared
inside of the chomp function call; it is fairly
common to declare each my variable as it is
needed, like this.
This is another case where chomp is vital. If
someone enters the five-character string "fred\n"
and we fail to chomp it, we'll be looking
for "fred\n" as an element of the hash -- and
it's not there. Of course, chomp alone
won't make this bulletproof; if someone enters "fred
\n" (with a trailing space), we don't have a way with
what we've seen so far to tell that they meant
fred.
If you added a check whether the given key exists
in the hash, so that you'll give the user an explanatory
message when they misspell a name, give yourself extra points for
that.
Here's one way to do it:
my(@words, %count, $word); # (optionally) declare our variables
chomp(@words = <STDIN>);
foreach $word (@words) {
$count{$word} += 1; # or $count{$word} = $count{$word} + 1;
}
foreach $word (keys %count) { # or sort keys %count
print "$word was seen $count{$word} times.\n";
}
In this one, we declared all of the variables at the top. People who
come to Perl from a background in languages like Pascal (where
variables are always declared "at the top") may find that
way more familiar than declaring variables as they are needed. Of
course, we're declaring these because we're pretending
that use strict may be in effect; by default, Perl
won't require such declarations.
Next, we use the line-input operator,
<STDIN>, in a list context to read all of
the input lines into @words, and then we
chomp those all at once. So
@words is our list of words from the input (if the
words were all on separate lines, as they should have been, of
course).
Now, the first foreach loop goes through all of the words. That loop
contains the most important statement of the entire program, the
statement that says to add one to $count{$word},
and put the result back into $count{$word}.
Although you could write it either the short way (with the
+= operator) or the long way, the short way is
just a little bit more efficient, since Perl has to look up
$word in the hash just once.[384]
For each word in the first foreach loop, we add
one to $count{$word}. So, if the first word is
fred, we add one to
$count{"fred"}. Of course, since this is the first
time we've seen $count{"fred"}, it's
undef. But since we're treating it as a
number (with the numeric += operator, or with
+, if you wrote it the long way), Perl converts
undef to 0 for us,
automatically. The total is 1, which is then
stored back into $count{"fred"}.
The next time through that foreach loop,
let's say the word is barney. So, we add one
to $count{"barney"}, bumping it up from
undef to 1, as well.
Now let's say the next word is fred again.
When we add one to $count{"fred"}, which is
already 1, we get 2. This goes
back into $count{"fred"}, meaning that we've
now seen fred twice.
When we finish the first foreach loop, then,
we've counted how many times each word has appeared. The hash
has a key for each (unique) word from the input, and the
corresponding value is the number of times that word appeared.
So now, the second foreach loop goes through the
keys of the hash, which are the unique words from the input. In this
loop, we'll see each different word once.
For each one, it says something like "fred was seen 3
times."
If you want the extra credit on this problem, you could put
sort before keys to print out
the keys in order. If there will be more than a dozen items in an
output list, it's generally a good idea for them to be sorted,
so that a human being who is trying to debug the program will fairly
quickly be able to find the item he or she wants.