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

Ohh wise monks!
I have 2 hashes that I want to print (if the keys match) together on a single line and also if they dont match at all print out the single key.
ie
KeyA.KeyB
KeyA
KeyB
KeyB.KeyA
etc....
Any knowledge you could give to a humble apprentice would be apperciated!

update (broquaint): title change (was A man walks into a bar with a hash under each arm!)

Replies are listed 'Best First'.
•Re: Hash key intersection
by merlyn (Sage) on Dec 30, 2003 at 17:01 UTC
Re: Hash key intersection
by talexb (Chancellor) on Dec 30, 2003 at 16:27 UTC

    Have a look in the camel or the Perl Cookbook for some pointers on answering this. Alternatively, try searching this site for how to do a hash intersection. Think about a loop that looks at one hash's keys and uses each one to look at the other hash. Try a few things, and let us know what you find out.

    Alex / talexb / Toronto

    Life is short: get busy!

    ps I love the title, but I've suggested a change to the more sober 'Hash intersection'.

Re: Hash key intersection
by kesterkester (Hermit) on Dec 30, 2003 at 16:42 UTC
    Here are two techniques (from the Perl Cookbook) that might point you in the right direction.

    use warnings; use strict; my %hash_a = ( one => 'a1', two => 'a2', three => 'a3', five => 'a5', ); my %hash_b = ( one => 'b1', two => 'b2', three => 'b3', four => 'b4', ); suba (); subb (); sub suba { my ( @common, @uncommon ) = ( (), () ); foreach ( keys %hash_a ) { push @common, $_ if exists $hash_b{$_}; push @uncommon, $_ if not exists $hash_b{$_}; } foreach ( keys %hash_b ) { push @uncommon, $_ if not exists $hash_a{$_}; } print "in both: @common\n not in both: @uncommon\n\n"; } sub subb { my @common = grep { exists $hash_b{$_} } keys %hash_a; my @uncommon = grep { not exists $hash_b{$_} } keys %hash_a; push @uncommon, (grep { not exists $hash_a{$_} } keys %hash_b); print "in both: @common\n not in both: @uncommon\n\n"; }

    The output is:

    in both: three one two
    not in both: five four

    in both: three one two
    not in both: five four

Re: Hash key intersection
by davido (Cardinal) on Dec 30, 2003 at 16:59 UTC
    I didn't realize that school was back in session already.

    How about:

    foreach ( keys %hash1 ) { my $out = ( exists $hash2{$_} ) ? $hash1{$_} . "." . $hash2{$_} : $hash1{$_} ; print $out, "\n"; }

    This assumes that if a key exists its value is defined. It also assumes that what you really meant was that you want to print the value associated with the keys in the respective hashes.

    I hope I haven't robbed you of your opportunity for an education. ;) See perldata, exists, keys, perlsyn, and perlop for an understanding at the mechanisms at work in this snippet. If your professor hasn't discussed the ternary operator yet, you may need to be able to explain how you know about it and how to use it. That's found in perlop.


    Dave

Re: Hash key intersection
by Nkuvu (Priest) on Dec 30, 2003 at 16:08 UTC
    So what have you tried so far?
Re: Hash key intersection
by BrowserUk (Patriarch) on Dec 30, 2003 at 19:53 UTC
    my @A{ qw[ 1 3 5 6 ] } = (); my @B{ qw[ 1 2 3 4 6 7 ] } = (); print join'.', ( exists $A{ $_ } ? 'A:' . $_ : ' ' ), ( exists $B{ $_ } ? 'B:' . $_ : ' ' ) for sort keys %{ { %A, %B } }; A:1.B:1 .B:2 A:3.B:3 .B:4 A:5. A:6.B:6 .B:7

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!

      sort keys %{ { %A, %B } }
      You'll get some spurious responses if %A and %B have values there, because you're mixing keys and values into a keys pile. Perhaps you wanted to add keys in front of each of the hashnames?

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


      update: OK, yeah, totally off base on this one. What was I thinking? {grin}

        Actually, it's important that you don't use keys in front of the individual hashes, otherwise alternate keys get used as values in the construction of the anonymous hash.

        As I as showed, but with values added you get

        @A{ qw[ 1 2 4 6 ] } = qw[ a b d f ]; @B{ qw[ 1 2 3 4 6 7 ] } = qw[ a b c d f g ]; print join '.', ( exists $A{ $_ } ? 'A:' . $_ : ' ' ), ( exists $B{ $_ } ? 'B:' . $_ : ' ' ) for sort keys %{ { %A, %B } }; A:1.B:1 A:2.B:2 .B:3 A:4.B:4 A:6.B:6 .B:7

        But using the extra key statements you get

        print join'.', ( exists $A{ $_ } ? 'A:' . $_ : ' ' ), ( exists $B{ $_ } ? 'B:' . $_ : ' ' ) for sort keys %{ { keys %A, keys %B } }; A:1.B:1 A:6.B:6 .B:7

        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        Hooray!

Re: Hash key intersection
by ysth (Canon) on Dec 30, 2003 at 20:49 UTC
    Your problem is a little unclear. If the keys are both "foo", you want to print "foo.foo"? or "foofoo"? or do you mean you want the associated values printed? If the latter, how would you tell whether you want A.B or B.A (you give examples of both). Are there any constraints on how you want the output ordered?
Smells Like Teen Homework?
by Anonymous Monk on Dec 30, 2003 at 16:31 UTC

    I'll give you the answer to that question, Mr. Bender, next Saturday. Don't mess with the bull young man, you'll get the horns.

    Vernon leaves.