#!/usr/bin/perl -w # To the student: # # This tutorial has been written given the assumption that you # are familiar with what a hash is and what some of the hash # oriented functions are. It is NOT written to teach you how # to use a hash in it's most basic form! If you need help with # that, refer to Perl's documentation or your instructor's # notes. # # Every attempt has been made to ensure that the information # presented in this code example is correct and syntactically # valid. You can yank and paste this code into your text editor # and run it directly on your own machine. Please report any # errors to kaiw@voyager.deanza.edu # # ~Kai # ################# THREE BASIC USES OF HASHES #################### # # First, let's review what a hash actually is. Functionally, # it is equivalent to an orderless array. Data in a hash can be # accessed when provided with a particular index. This index is # called a KEY. Each key is associated with a particular value, # setting up what is called a key/value pair. # # NOTE: A key cannot have more than one value, nor can the same # key modify two values at the same time! # # Just like a phone book has a name which then corresponds to # a phone number, a hash has a key associated to a value. Now # that we have the basic uses of hashes down, lets see when # you as the Perl programmer would want to use one: ############ SITUATION 1: TEXT INDEXING ########### # # Let's say we want to store some bank sums from different people # into some sort of a usable structure. We could set up two # parallel lists, one with their names, the second with their # corresponding bank balances in the matching index. So # Mr. Andresen has a balance of $10,000.00 and # Ms. Skougaard has a paltry balance of $20.00. my ( @names, @balances ); @names = ( "Andresen", "Agarwal", "Nguyen", "Skougaard" ); @balances = ( 10000.00 , 15000.00 , 8000.00 , 20.00 ); # Print the balances print "Current Balances (from lists):\n"; foreach $i ( 0..@names-1 ) ## Note: without the random -1, we would { ## run off by one! print "$names[$i]: $balances[$i]\n"; } # Increase Mrs. Skougaard's balance by $10,000 # First locate her index $i = 0; # Reset i's value to zero. foreach $name ( @names ) { last if $name =~ /Skougaard/; ## Yuck. Seriously don't do this. $i++; } $balances[$i] += 10000.00; # Now update her balance # We see with an arrangement like this the data can certainly be # represented in memory, but not very effectively. To print the # values, you would have to index through each array, which can # be quite tedious. In addition, both lists would have to be # maintained in parallel! This introduces the possibilities for # off-by-one errors, not to mention it makes NO use of Perl's # basic constructs like standard list traversal. # ### BRING IN THE HASH ### # # Instead of the awful (but functional example above, let's try # this intead: my %bankBalances; ## "key" => "value" %balances = ( "Andresen" => 10000.00, "Agarwal" => 15000.00, "Nguyen" => 8000.00, "Skougaard"=> 20.00 ); # Print the balances print "\nCurrent Balances (from hash):\n"; foreach $name ( sort keys %balances ) { print "$name: $balances{$name}\n"; } # Increase Mrs. Skougaard's balance by $10,000 $balances{ "Skougaard" } += 10000.00; # That's it! # Look at how much cleaner and easier this is to manage! We # can easily print the hash and access the hash data! The # keys function gets the "keys" to the values, and sort # simply puts those keys in a default order. # # One thing to note: You can NOT perform sequential data # processing with a hash, as a hash is inherently unordered! # So when you're using the keys function, unless they're # sorted, the hash keys will come in RANDOM ORDER! This also # means that you cannot use list oriented functions directly # on the hash itself. However, there are still nifty things # to do with hashes and list oriented functions. More on # that in a different tutorial. ############ SITUATION 2: COUNTING ########### # # Perhaps we have more data we need to process for these # fine people. Let us imagine that they are with # Bank of America and BofA leverages a 20 cent charge for # each time they use their debit card. We'll say that each # time they charge onto debit, their name gets pushed onto # a list, and we want to count how many times one person # charged. @charges = ( "Andresen","Agarwal","Agarwal","Agarwal","Andresen","Agarwal" ); # I don't even want to think of how to count this with a # list. In fact, it's a waste of time for you to even think # about how to do it with a list. It, again, would require # a parallel list mess and would suck down compute time. # Lets use a hash instead! my %chargeCounter; foreach $person ( @charges ) { $chargeCounter{$person}++; } print "\nCharge count:\n"; foreach $person ( sort keys %chargeCounter ) { print "$person charged $chargeCounter{$person} times.\n"; } # As we can see, this makes use of the basic Perl rule that # the first time you use a value it is auto-initialised to # undefined (zero in a numeric context)! This quickly counts # the names in the array! ############ SITUATION 3: DUPLICATE CHECKING AND FILTERING ############ # # For this third and final task we are going to weed duplicates out of # an array. There can be many situations where you need to do this. # This is really just a logical extension from above. So to extend off # the situational example above, we'll say there's a charge list, but # now we're tasked with charging each person who has used their debit # card ONE OR MORE TIMES the standard Bank of America fee of $5.00. We # are not evil so therefore don't want to charge them $5.00 for each # use DO WE? # # No, so let us filter out the duplicates from the same list: @charges = ( "Andresen","Agarwal","Agarwal","Agarwal","Andresen","Agarwal" ); my %debitUsed; foreach $person ( @charges ) { $debitUsed{$person} = 1; ## NOTE: this is almost identical to above! ## In fact, you'll see soon that we can really ## use the same hash from above for duplicate ## checking. } @chargeThesePeople = keys %debitUsed; print "\nCharge these people \$5.00: @chargeThesePeople\n"; # Notice, if we want to, we can easily use this hash in a boolean/integer # context. Any value that is not undefined is true, so it makes it simple # to do these if tests: if ( $debitUsed{"Andresen"} ) { print "Andresen used his debit card.\n" } else { print "Andresen did NOT use his debit card.\n" } if ( $debitUsed{"Skougaard"} ) { print "Skougaard used her debit card.\n" } else { print "Skougaard did NOT use her debit card.\n" } ##################### IN CLOSING ########################## # # As you can see, hashes are a very powerful part of Perl. This # is again only some of the BASIC usages of hashing. There are # many more advanced techniques that can be employed. I invite # you all to share with me any other ways you might have # used a Perl hash.