Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Common hash keys

by Anonymous Monk
on Jun 07, 2008 at 07:16 UTC ( [id://690802]=perlquestion: print w/replies, xml ) Need Help??

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

Given two hash references, how can I determine if they have any keys in common?

Replies are listed 'Best First'.
Re: Common hash keys
by moritz (Cardinal) on Jun 07, 2008 at 07:36 UTC
    This is described (in a slight variation) in perlfaq4. If you have problems with having references and not the hash itself, read perlreftut.
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Common hash keys
by apl (Monsignor) on Jun 07, 2008 at 12:33 UTC
    Ignoring CPAN modules, If you can't think of at least two purely mechanical ways of solving this problem, you need to either read (among other things) Data Type: Hash, or drop the class you're in.
Re: Common hash keys
by throop (Chaplain) on Jun 07, 2008 at 13:23 UTC
    use strict; use vars qw($hashRef1 $hashRef2); #code that puts values into the hashes my @keyIntersection = grep exists($hashRef2->{$_}), keys %$hashRef1; # Or if you just want to know if there are any use List::Util; my $hasInt = first {exists $hashRef2->{$_}} keys %$hashRef1;
    $hasInt will be undef unless there's an intersection.
    But be careful, it will be 0 if the first interecting key is '0'

    throop

      There's no need to be careful if you handle the 0 case directly:

      use List::Util; my $hasInt = defined first { exists $hashRef2->{$_} } keys %$hashRef1 ;

      lodin

        Actually, there's no need to be careful or test for definedness.

        List::Util::first() returns the result of the code block, in this case the boolean return of the exists function. The values associated with the keys never come into it.

        use List::Util qw[ first ];; my $a = { a=>0, b=>0, c=>0 }; my $b = { c=>0, d=>0, e=>0 }; if( first{ exists $b->{ $_ } } keys %$a ) { print "Common keys!"; } Common keys!

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

      *That's the one*. Thank you.

      use List::Util 'first'; if(first{exists $hashRef2->{$_}} keys %$hashRef1 ) # }
Re: Common hash keys
by ferreira (Chaplain) on Jun 07, 2008 at 14:45 UTC

    It should be as simple as that:

    my @common_keys = grep { exists $hash1->{$_} } keys %$hash2;
Re: Common hash keys
by casiano (Pilgrim) on Jun 07, 2008 at 10:01 UTC
    If you want to know which keys they have in common:
    DB<1> %a = (a => 1, b =>2, c => 3); %b = (b =>2, c => 1, d => 4) DB<2> $seen{$_}++ for (keys(%a), keys(%b)) DB<3> x grep { $seen{$_} > 1 } keys(%seen) 0 'c' 1 'b'
    If the only thing you want is to know if they have some key in common:
    DB<1> use List::Util qw{first} DB<2> %a = (a => 1, b =>2, c => 3); %b = (b =>2, c => 1, d => 4) DB<3> x first { ++$seen{$_} > 1 } (keys(%a), keys(%b)) 0 'c'
    Hope it helps

      DB<2> $seen{$_}++ for (keys(%a), keys(%b)) DB<3> x grep { $seen{$_} > 1 } keys(%seen)
      You can combine these two into a single statement:
      use Data::Dump; my %a = ( a => 1, b => 2, c => 3 ); my %b = ( b => 2, c => 1, d => 4 ); my %seen; pp grep { $seen{$_}++ } keys %a, keys %b;

      Update: Don't use state variables for this. See lodin's reply

      Or, with 5.10

      pp grep { state %seen; $seen{$_}++ } keys %a, keys %b;

      Unless I state otherwise, all my code runs with strict and warnings

        Be careful with that state. It won't do what (I think) you want.

        use 5.010; sub foo { my ($a, $b) = @_; sort grep { state %seen; $seen{$_}++ } keys %$a, keys %$b } my %a = ( a => 1, b => 2, c => 3 ); my %b = ( b => 2, c => 1, d => 4 ); say join ' ', foo(\%a, \%b); say join ' ', foo(\%a, \%b); __END__ b c a b b c c d
        Here you should just stick with my.

        lodin

Re: Common hash keys
by parv (Parson) on Jun 07, 2008 at 07:30 UTC

    What have you tried? Pseudocode would be ...

    for all keys in hash-1, where k-1 is current key for all keys in hash-2, where k-2 is current key put k-1 in store if k-1 = k-2 end-for end-for # "store" would have all the common keys in the end

    Time passes. Oh yes, finding if any keys are present ...

    common set to false for all keys in hash-1, where k-1 is current key for all keys in hash-2, where k-2 is current key if k-1 = k-2, common set to true break out of both loops end-for end-for # test common to check for commonality
      Your inner loop could be described as clubbing somebody to death with a loaded uzi. No need to iterate over the hash keys just to check if one is present. Looking up a key in a hash is the most basic operation a hash offers ;-)

        (: Indeed! (But I did not write Perl, did I?)

Re: Common hash keys
by radiantmatrix (Parson) on Jun 09, 2008 at 20:46 UTC

    OK, let's walk through this.

    A hash reference is just a reference to a hash, getting at the hash is a simple matter -- so we can ignore the "reference" part of your question for now, and focus on how to determine if two hashes share any keys. Let's start with two simple hashes:

    %a = ( one=>1, two=>2, three=> 3 ); %b = ( two=>'two', three=>'three', four=>'four');

    We know the keys they have in common are two and three, but how to find that out in code?

    First, let's rephrase the question a little bit: if I know all the keys in one hash, how do I find out if any of those keys exist in another hash?

    Let's work backwards from that. How do we find out if the %a hash contains a key -- let's say, the key one? That would be exists:

    if (exists $a{one}) { print "\%a has 'one' for a key" }

    Ok, so how do we find out what keys a hash has? How about keys:

    print join(",", keys %a); # prints "one,two,three"

    So, if we get the list of keys for hash %a, all we have to do is loop through them and see if %b has any that match. Here's the long way:

    my @common_keys; foreach my $key (keys %a) { if (exists $b{$key}) { print "\%a and \%b have key '$key' in common\n"; push @common_keys, $key; } }

    Make sense? Of course, this type of activity -- looking through a list to find items that meet a criterion -- is so common that Perl has a function for it: grep. So here's a short version:

    my @common_keys = grep { exists $b{$_} } keys(%a);

    Now let's add "references" back to the mix. Let's make references to our hashes:

    $x = \%a; $y = \%b;

    Now, we do as above, but dereferencing as appropriate:

    my @common_keys = grep { exists $y->{$_} } keys( %{ $x } );

    We pass the whole hash referenced by $x to keys; and we use the dereference operator -> to make sure that exists looks at the hash referenced by $y.

    <radiant.matrix>
    Ramblings and references
    “A positive attitude may not solve all your problems, but it will annoy enough people to make it worth the effort.” — Herm Albright
    I haven't found a problem yet that can't be solved by a well-placed trebuchet
Re: Common hash keys
by injunjoel (Priest) on Jun 08, 2008 at 20:46 UTC
    For the sake of esoteric aesthetics...
    #!/usr/bin/perl -w use strict; my %a = ('a' =>1, 'b'=>2, 'c'=>5, 'd'=>19); my %b = ('b'=>12, 'd'=>32, 'z'=>77, 'y'=>5); my @common_keys = do{ local %_; $_{$_}++ for(keys %a, keys %b); delete @_{(map{ ($_{$_} == 1) ? $_ : ()}keys %_)}; sort keys %_; }; print "@common_keys";
    -InjunJoel
    "I do not feel obliged to believe that the same God who endowed us with sense, reason and intellect has intended us to forego their use." -Galileo
Re: Common hash keys
by wade (Pilgrim) on Jun 09, 2008 at 16:06 UTC

    Is it possible, given that the OP was so terse and so aggressive (in later posts, though I admit that I'm making assumptions), that this is a troll?

    --
    Wade
      And look at who was aggressively defending the aggressive troll...

        Ooooh Mummy. He's soo harsh and aggressive. He said I didn't understand hashes and that he'd wait for a better answer.

        Mummy. Make the bad man go away.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2024-03-29 01:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found