Hash Mania With Perl - Subbing Out Sorting
(Page 4 of 4 )
Think it will introduce too many typos to remember the construct for alphabetical sorting? Then "sub" it! Let's say you use sorting very frequently in your programming and find it cumbersome to type in the above operations each time.
Let's handle this by example:
foreach my $key (sort ascend_alpha keys %hash){
print "$key = $hash{$key}
";
}
You can easily see that the lc($a) cmp lc($b) has been replaced by a subroutine call. Now, let's consider the following:
sub ascend_num
{$a <=> $b}
sub descend_num {$b <=> $a}
sub ascend_alpha {lc($a) cmp lc($b)}
sub descend_alpha {lc($b) cmp lc($a)}
sub ascend_alphanum {$a <=> $b || lc($a) cmp lc($b)}
sub descend_alphanum {$b <=> $a || lc($b) cmp lc($a)}
The ascend_alphanum and descend_alphanum routines sort both alphabetically and numerically, so if you added "5 Spice Seasoning", "1 Star Flour", and "911 Hot Sauce" to %hash, it will sort the numbers numerically in addition to letters alphabetically.
Apples = 1
apples = 4
artichokes = 3
Beets = 9
canadian = 9
5 Spice Seasoning = 1
10 Star Flour = 1
911 Hot Sauce = 1
Working with Hash References Have a hash reference and don't want to duplicate the subroutines to deal with them? It's easy... just pass the dereferenced keys to the sort routines:
$hashref
= %hash;
foreach my $key (sort ascend_alpha keys %{$hashref}){
print "$key = $hashref->{$key}
";
}
Notice the hash deference %{$hashref} and the arrow dereferencer for the value $hashref->{$key}.
Sorting by Hash Values What if you wanted to sort the values instead of the keys? Consider the following:
foreach my $key (sort {$hash{$a} <=> $hash{$b}} keys %hash){
print "$key = $hash{$key}
";
}
This will print out:
Apples = 1
5 Spice Seasoning = 1
10 Star Flour = 1
APples = 2
artichokes = 3
apples = 4
911 Hot Sauce = 4
canadian = 9
Beets = 9
But let's say you also had text values -- let's change $hash{'Beets'} to "cans: 4 - 8.oz." and $hash{'Apples'} to "Delicious Red - 4 medium sized". You can have the hash sorted numerically and alphabetically by using the following:
foreach my $key (sort {$hash{$a} <=> $hash{$b} || $hash{$a} cmp $hash{$b}} keys %hash){
print "$key = $hash{$key}
";
}
This will correctly print out:
Beets = cans: 4 - 8.oz.
Apples = Delicious Red - 4 medium sized
5 Spice Seasoning = 1
10 Star Flour = 1
APples = 2
artichokes = 3
apples = 4
911 Hot Sauce = 4
canadian = 9
Multidimensional Hashes Using key/value pairs is great, but what if you wanted to associate more than one value to a key? Using a slightly different construct, you can essentially use an array as a key's value:
%hash = (
Apples => [4, "Delicious red", "medium"],
"Canadian Bacon" => [1, "package", "1/2 pound"],
artichokes => [3, "cans", "8.oz."],
Beets => [4, "cans", "8.oz."],
"5 Spice Seasoning" => [1, "bottle", "3 oz."],
"10 Star Flour" => [1, "package", "16 oz."],
"911 Hot Sauce" => [1, "bottle", "8 oz."],
);
Now, to extract the values, you can treat them as an array of the hash:
print $hash{"Canadian Bacon"}[1];
...will print package, because package is the second element of Canadian Bacon's "array". You can also add an predefined array to a hash value:
@garlicstuff = (4, "cloves", "medium");
$hash{"Garlic"} = [@garlicstuff];
print $hash{"Garlic"}[1]; # prints cloves
But what if @garlicstuff had more elements than others? Let's say that @garlicstuff is
@garlicstuff = (4, "cloves", "medium", "chopped");
instead? How do we print out all values for a key if one key can have 3 values, and another has 4 (or more) values?
foreach my $key (sort ascend_alpha keys %hash){
print "$key:
";
foreach my $val (@{$hash{$key}}){
print " $val
";
}
print "
";
}
Because a multidimensional array's values are essentially arrays, a key's group of values can be dereferenced by using @{$hash{$key}}. The above code prints:
10 Star Flour:
1
package
16 oz.
5 Spice Seasoning:
1
bottle
3 oz.
911 Hot Sauce:
1
bottle
8 oz.
Apples:
4
Delicious red
medium
artichokes:
3
cans
8.oz.
Beets:
4
cans
8.oz.
Canadian Bacon:
1
package
1/2 pound
Garlic:
4
cloves
medium
chopped
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |