http://www.perlmonks.org?node_id=90616


in reply to Hash Tutorial

The fundamental key IMHO is this. As long as you are doing a lot of thinking involving positional logic, you are not being very Perlish. What this means is that you use implicit looping operations (foreach over a list rather than a C-style for, map, grep) and use hashes to do things by name. To get a good sense I can suggest nothing better than getting the Cookbook and looking through the examples in there.

Short of that I highly recommend the section in Camel II (possibly in Camel III as well?) in chapter 1 on how Perl data structures map to linguistic operations. The linguistic version of a hashlookup is the word "of". This informs us how we name a hash. If the hash gives us the address of the person, we should say $address{$person}. If it is possible to get an address in several ways we might be more verbose and say $address_by_person{$person}. In either case "talk your way" through the problem in English and wherever you say "of" or an equivalent, that is a good sign that you want a hash.

That said, here are some standard uses that I have for them:

  1. The obvious lookup. $address{$person};
  2. Keep track of existing things I have dealt with. Where I might say, "If I haven't seen this one yet (BTW mark it seen) then..." I might write in code: if (not $is_seen{$case}++) { # etc
  3. Named function arguments. Rather than having to remember a set of 6 arguments in order, and what the defaults are if you need to set the 6'th but not touch the 3'rd, 4'th, or 5'th, just use a hash:
    sub my_function { my %opts = @_; # etc
    and it is easier to remember how to call the function, and easier to add more useful options later.
  4. Structs. Anywhere you would have used a pointer to a struct in C, you can use a reference to a hash in Perl. The notation is even similar since the arrow is used in Perl for dereferencing. This is why you see a lot of OO code in Perl with things like: my $name = $self->{name};
  5. List special cases. You can easily enumerate special cases in a hash. If you are willing to create anonymous functions for them (with sub) then you can easily create a nice catch-all special case:
    if (exists $handler{$case}) { $handler{$case}->(); # Handle the special case }
    The actual definitions of the special cases are placed elsewhere. Lest this idea just sound weird, you may want to read Why I like functional programming. (It helps to read the *last* function first - scrub_input - and understand what it does. It may also help to check out what pos does.) OK, perhaps you don't want to try that. Yet.
And so it goes. Whenever it makes sense to refer to things by name, it makes sense to use hashes.

UPDATE
Forgot a ++ on $is_seen{$case}. I thought it, and verbalized it in English, but when I went to write the Perl at last I apparently forgot it at the last moment...

Replies are listed 'Best First'.
Re: Re (tilly) 1: Hash Tutorial
by jreades (Friar) on Jun 22, 2001 at 18:28 UTC
    The fundamental key IMHO is this. As long as you are doing a lot of thinking involving positional logic, you are not being very Perlish.

    I just wanted to qualify this statement with a slightly tangential one of my own -- as a newbie, when you discover the power of hashes in Perl they become intoxicating. Oh, this could be a hash. Oh, and so can this. And this. And this. And...

    tilly's very erudite description of the hash glosses over this slightly, but only because, as a saint, he's probably forgotten how we men and women in the trenches think.

    It is important to remember that hashes have higher overhead and are slower to access than an array, but, in contrast, accessing a hash is essentially a constant time operation -- meaning, that as long as I know what item I want, it takes the same amount of time to access the 1st element of the hash as the nth.

    There is a lot of overlap between arrays and hashes conceptually in Perl (and even more so under the hood), and you need to keep in mind how you are intending to use your data structure and the kind of data it will hold. For instance, a few general examples:

    • When order is important for adding/accessing: array
    • When keyword access is important for adding/accessing: hash
    • When numeric values are your keys: dense data = array, sparse data = hash

    The rules/ideas go on for many lines from there, but I guess what I'm getting at, is that Perl makes it possible to see the world through hash-tinted glasses <pun intended>, but always keep in mind that the lowly array is an equally adept tool for many jobs.