in reply to Hash table question

Assume %hash1 and %hash2 are already defined with the data you need:

elements common between two tables

my @common = grep { $_ if exists $hash2{$_} } keys %hash1;

elements unique to table #1

my @unique1 = grep { $_ unless exists $hash2{$_} } keys %hash1;

elements unique to table #2

my @unique2 = grep { $_ unless exists $hash1{$_} } keys %hash2;

----
I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
-- Schemer

Note: All code is untested, unless otherwise stated

Replies are listed 'Best First'.
•Re: Re: Hash table question
by merlyn (Sage) on Jun 24, 2003 at 16:58 UTC
    Uh, not quite. You'll be throwing away any false key ("", "0").

    You want:

    my @common = grep exists $hash2{$_}, keys %hash1; my @unique1 = grep !exists $hash2{$_}, keys %hash1; my @unique2 = grep !exists $hash1{$_}, keys %hash2;
    But if you really want all three at once:
    my %t; $t{$_} .= "1" for keys %hash1; $t{$_} .= "2" for keys %hash2;
    And then each element of %t will be "1" for 1 only, "2" for 2 only, or "12" for both.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: Re: Hash table question
by halley (Prior) on Jun 24, 2003 at 16:58 UTC
    This is indeed proper*, and is quite efficient. Without needlessly and prematurely optimizing, for the first case, one might consider checking (scalar keys %hash1) <=> (scalar keys %hash2) and perform the constraining loop on the smaller hash. This would only have a significant benefit if the discrepancy in hash sizes is significant.

    * (Except the wreck if it finds the false keys of '' and '0', as merlyn mentioned.)

    Update: Separately, I agree that grep also works as a perl-idiom alternative to foreach, but that shouldn't change the actual effectiveness to my knowledge.

    --
    [ e d @ h a l l e y . c c ]