Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Hash slices ?

by ChOas (Curate)
on Dec 01, 2000 at 15:27 UTC ( [id://44328]=perlquestion: print w/replies, xml ) Need Help??

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

This results from a discussion in the chatterbox
Please help me on this one, can someone explain to
me the result of the following code:
#!/usr/bin/perl -w use strict; my @keys = qw(one two three); my %hash = ( four => 4, five => 5, six => 6); print "@keys\n"; if (@hash{@keys}) { print "yep\n"; } else { print "nope\n"; } push @keys, 'four'; print "@keys\n"; if (@hash{@keys}) { print "yep\n"; } else { print "nope\n"; } @keys = qw(one two three); unshift @keys,'four'; print "@keys\n"; if (@hash{@keys}) { print "yep\n"; } else { print "nope\n"; }

Result:
martijn@xxxx$ ./test
one two three
nope
one two three four
yep
four one two three
nope

Strange innit ?

Replies are listed 'Best First'.
Re: Hash slices ?
by kilinrax (Deacon) on Dec 01, 2000 at 17:30 UTC
    Adding a couple more tests to your script gives us a clue:
    @keys = qw(one two five); unshift @keys,'four'; print "@keys\n"; if (@hash{@keys}) { print "yep\n"; } else { print "nope\n"; } @keys = qw(one two five); push @keys, 'two'; print "@keys\n"; if (@hash{@keys}) { print "yep\n"; } else { print "nope\n"; }
    Gives the result:
    four one two five yep one two five two nope
    It would appear that only the presence of the last key in the array is affecting whether the test returns true or false.

    I would suggest a possible solution would be to abuse grep, thus:
    if ( grep{ exists( $hash{$_} ) } @keys ) { print "yep\n"; } else { print "nope\n"; }
      Ayup -- it's the last key that matters, just as if the hash slice were being treated as a list -- evaluate a list in a scalar context and it returns the last value.

      There's nothing in the docs that I could find that says that a hash slice would be interpreted as a list rather than a proper array, but it does apear to be the case.

        Any one further investigation, it seems that my original solution suffered from a fundamental problem.

        my %hash = (one => 1, two => 2, three => 3); my @keys = qw(four five six); my @slice = @hash{@keys};

        @slice is now contains four undef elements, where I thought it would be an empty list (don't know why I thought that - it was very early in the morning.

        If the hash slice was interpreted as an array, it would therefore always be true and therefore doesn't solve ChOas' original problem. That would be better addressed using something like:

        if (grep { exists %hash{$_} } @keys) { print "yep\n"; } else { print "nope\n"; }
        --
        <http://www.dave.org.uk>

        "Perl makes the fun jobs fun
        and the boring jobs bearable" - me

        Well, we always go around about this, because the perldata does clearly say:
        @days # ($days[0], $days[1],... $days[n]) @days[3,4,5] # same as @days[3..5] @days{'a','c'} # same as ($days{'a'},$days{'c'})
        See the "same as"? That's the operative words. To make it the same, it has to return the last element of the list in a scalar context. So yes, the behavior is documented, and derivable from the docs.

        -- Randal L. Schwartz, Perl hacker

Re: Hash slices ?
by ChOas (Curate) on Dec 01, 2000 at 15:38 UTC
    The original discussion for this one
    started with my question: how do I find if
    at least one of many keys in a list is in a hash
    (quick, fast, and simple)
    davorg offered me a working example, but when I
    tried it, I inserted the 'four' at the start of the list
    which didn't work
    The push on the other hand DID.
    and as you can see the unshift doesn't work either

    Many thanks davorg !!
    Let's see what people can tell us about this one ;))

      how do I find if at least one of many keys in a list is in a hash (quick, fast, and simple)

      Dunno if this meets *all* of your criteria, but I find this simple enough:

      my @search_keys = qw(one two three); my %hash = ( four=>4, five=>5, six=>6); my $foundit =0; foreach (@search_keys) { if (exists $hash{$_}) { $foundit =1; print "found an entry for $_ in %hash!\n"; } }

      Philosophy can be made out of anything. Or less -- Jerry A. Fodor

        Given that the idea is to find out if any of the keys exist in the hash, it would be more efficient to call last and exit the loop once you've found one.

        --
        <http://www.dave.org.uk>

        "Perl makes the fun jobs fun
        and the boring jobs bearable" - me

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://44328]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (7)
As of 2024-03-19 02:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found