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. | [reply] [Watch: Dir/Any] |
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. | [reply] [Watch: Dir/Any] |
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 | [reply] [Watch: Dir/Any] [d/l] |
|
use List::Util;
my $hasInt =
defined
first { exists $hashRef2->{$_} }
keys %$hashRef1
;
lodin | [reply] [Watch: Dir/Any] [d/l] |
|
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
use List::Util 'first';
if(first{exists $hashRef2->{$_}} keys %$hashRef1 )
#
}
| [reply] [Watch: Dir/Any] [d/l] |
Re: Common hash keys
by ferreira (Chaplain) on Jun 07, 2008 at 14:45 UTC
|
my @common_keys = grep { exists $hash1->{$_} } keys %$hash2;
| [reply] [Watch: Dir/Any] [d/l] |
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
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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;
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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 | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Common hash keys
by parv (Parson) on Jun 07, 2008 at 07:30 UTC
|
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
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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 ;-)
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
|
|
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
| [reply] [Watch: Dir/Any] [d/l] [select] |
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
| [reply] [Watch: Dir/Any] [d/l] |
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?
| [reply] [Watch: Dir/Any] |
|
And look at who was aggressively defending the aggressive troll...
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |