Hagbone has asked for the wisdom of the Perl Monks concerning the following question:

Often, when coding scripts, I encounter situations where I need to test to see if a variable matches an item that's stored in a list of values.

One approach I've used is to maintain an array that is reviewed for the match using a "foreach" type iteration.

Another approach is to maintain a hash, and test for the presence of a hash value that matches.

It seems that using the second approach is more efficient from both an operating system standpoint, and a coding standpoint:
foreach (@whatever) { if (/^does this match$/) { do something; } }
Vs.
if (/$hash{$whatever}/) { do something; }
Assuming I'm thinking correctly so far, my next question has to do with creating the hash value. Is there anything "wrong" with populating a hash with keys and values that are the same? For example:
%SampleHash ( 'whatever' => 'whatever', 'whoever' => 'whoever', )
It feels like there's something wrong (or maybe more accurately, inefficient) using a hash this way, but I'm not smart enough to know if that is in fact true.

When I use hashes as described above, things seem to work OK ... I'm just wondering/hoping that some of the brainier participants here might be able to point out errors in my thinking, and/or more appropriate ways of how to handle this type of situation.

Replies are listed 'Best First'.
Re: Creating lists using a hash with the same key/values
by Trimbach (Curate) on Jan 01, 2003 at 23:53 UTC
    The idiom of using hashes as a fast and easy lookup table is a common one in Perl. Hashes are quick, easy to setup and lend themselves well to a boolean-type comparisons like what you're talking about.

    The only thing is your example of

    %SampleHash ( 'whatever' => 'whatever', 'whoever' => 'whoever', )
    is more commonly coded as
    %SampleHash ( 'whatever' => 1, 'whoever' => 1, )
    ...simply because if you ain't gonna be using the values of the hash, there's no reason to make the value any longer than absolutely necessary. Making the value a "1" does the trick, and it doesn't waste memory. Of course, you're probably not likely to have a hash of values that's so big for the memory cost to matter much, but hey, waste not want not. :-)

    Gary Blackburn
    Trained Killer

Re: Creating lists using a hash with the same key/values
by tachyon (Chancellor) on Jan 01, 2003 at 23:55 UTC

    Idiomatically you would do this:

    my @list = qw( foo bar baz ); my %hash; $hash{$_}++ for @list; # now do a lookup if ( $hash{$look_this_up} ) { # blah } use Data::Dumper; print Dumper \%hash __DATA__ $VAR1 = { 'foo' => '1', 'baz' => '1', 'bar' => '1' };

    This populates the hash with identical values (ie 1). It means that $hash{$value} will be true if $value is in the hash or false if it is not. We are really only interested in the keys for the fast lookup but having a true value lets us avoid having to use exists

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Creating lists using a hash with the same key/values
by atcroft (Abbot) on Jan 01, 2003 at 23:52 UTC

    Why not do something like $SampleHash{'whatever'}++;, so all you would have to do is say something along the lines of &whatever if ($SampleHash{'whatever'}); for instance...

Re: Creating lists using a hash with the same key/values
by djantzen (Priest) on Jan 02, 2003 at 00:01 UTC

    I tend to agree with your hesitation Hagbone. I try to avoid using hashes merely for looking up keys and throwing away the values, but that's mostly a religious perspective on my part, and in many cases that's the cleanest way to code a lookup function. A couple of observations: first, in this situation it is common to initialize the hash using a hash slice where your values are '1'. So,

    my %lookup_hash = (); %lookup_hash{@whatever} = (1) x @whatever;

    Secondly, a hash lookup is much faster than iterating through an array as the number of values increases. So, the "waste" of the values in a hash to gain lookup speed is sometimes a worthwhile tradeoff.

    Note that in your second example (if (/$hash{$whatever}/) ) you needn't do a match against the value returned from your hash; rather, merely check the key like so: if ($hash{$whatever}).

Re: Creating lists using a hash with the same key/values
by bart (Canon) on Jan 02, 2003 at 09:02 UTC
    Often, when coding scripts, I encounter situations where I need to test to see if a variable matches an item that's stored in a list of values.
    if (/$hash{$whatever}/) { do something; }
    Assuming I'm thinking correctly so far, my next question has to do with creating the hash value. Is there anything "wrong" with populating a hash with keys and values that are the same? For example:
    %SampleHash ( 'whatever' => 'whatever', 'whoever' => 'whoever', )
    The idea to use a hash to check if an item can be found in a set, is a good one. What is wrong with your last approach, is that if the string evaluates to false, a simple
    if($SampleHash{$string}){ ... }
    will fail to see it. The strings that do that, are "" and "0".

    I ordinarily use one of the following approaches:

    foreach(LIST) { $checked{$_}++; } if($checked{$string}) { ... }
    or
    @checked{LIST} = (); if(exists $check{$string}) { ... }
    but there are more. Use what seems most appropriate at the time.
Re: Creating lists using a hash with the same key/values
by gjb (Vicar) on Jan 02, 2003 at 00:22 UTC

    You may want to have a look at the Set::* family of modules, especially Set::Scalar and Set::Object come to mind.

    Hope this helps, -gjb-