sub card { my %card_map; @card_map{1..9} = qw( one two three four five six seven eight nine ); my($num) = @_; if ($card_map{$num}) { $card_map{$num}; # return value } else { $num; # return value } } # driver routine: while (<>) { chomp; print "card of $_ is ", &card($_), "\n"; }
The &card subroutine (so named because it returns a cardinal name for a given value) begins by initializing a constant hash called %card_map. This array has values such that $card_map{6} is six; consequently, the mapping is easy.
The if statement determines if the value is in range by looking the number up in the hash - if there's a corresponding hash element, the test is true, so that array element is returned. If there's no corresponding element (such as when $num is 11 or -4), the value returned from the hash lookup is undef, so the else-branch of the if statement is executed, returning the original number. You can also replace that entire if statement with the single expression:
$card_map{$num} || $num;If the value on the left of the || is true, it's the value for the entire expression, which then gets returned. If it's false (such as when $num is out of range), the right side of the || operator is evaluated, returning $num as the return value.
The driver routine takes successive lines, chomping off their newlines, and hands them one at a time to the &card routine, printing the result.
sub card { ...; } # from previous problem
print "Enter first number: ";
chomp($first = <STDIN>);
print "Enter second number: ";
chomp($second = <STDIN>);
$message = &card($first) . " plus " .
&card($second) . " equals " .
&card($first+$second) . ".\n";
print "\u$message";The first two print statements prompt for two numbers, with the immediately following statements reading the values into $first and $second.
A string called $message is then built up by calling &card three times, once for each value, and once for the sum.
After the message is constructed, its first character is uppercased by the case-shifting backslash operator \u. The message is then printed.
sub card {
my %card_map;
@card_map{0..9} = qw(
zero one two three four five six seven eight nine
);
my($num) = @_;
my($negative);
if ($num < 0) {
$negative = "negative ";
$num = - $num;
}
if ($card_map{$num}) {
$negative . $card_map{$num}; # return value
} else {
$negative . $num; # return value
}
}Here, we've given the %card_map array a name for 0.
The first if statement inverts the sign of $num, and sets $negative to the word negative, if the number is found to be less than 0. After this if statement, the value of $num is always non-negative, but we will have an appropriate prefix string in $negative.
The second if statement determines if the (now positive) $num is within the hash. If so, the resulting hash value is appended to the prefix within $negative, and returned. If not, the value within $negative is attached to the original number.
That last if statement can be replaced with the expression:
$negative . ($card_map{$num} || $num);