This is a typical intersection problem. Yes, a FAQ. Go read [doc://perlfaq4]. You basically create some arrays with the hash keys and perform the intersection over them.
Update: Hmm, seems I misread "values". Well, you can perform the intersection of the values as it's explained in the FAQ. For obtaining the corresponding keys, you can reverse the hash:
my %c = ( a=>1, b=>2, c=>3 );
my %rev_c = reverse %c;
use Data::Dumper;print Dumper \%rev_c;
__END__
$VAR1 = {
'1' => 'a',
'3' => 'c',
'2' => 'b'
};
Of course, you're going to have problems if there's more than one key with the same value, since the action of reversing the hash will eliminate all of those keys but one.
--
David Serrano
Use another hash to count the keys: (Corrected: Pre- not post-increment)
%h= 1..10; %i = 1.. 20; %j = 3..8; %k = 9 .. 18;; %l = 1 .. 14;;
%x = ();;
print grep{
++$x{ $_ } == 2
} sort{
$a <=> $b
} map{
keys %$_
} \( %h, %i, %j, %k, %l,);;
1 3 5 7 9 11 13 15 17
use strict;
use warnings;
my %hash1 = (a => 1, b => 2);
my %hash2 = (a => 1, c => 3);
my %hash3 = (d => 1, c => 3);
# Method 1
# Create a hash for tallying the number of times keys occur in the other hashes.
my %key_bucket = ();
for my $key (keys %hash1, keys %hash2, keys %hash3) {
$key_bucket{$key}++;
}
my @duplicates = grep {$key_bucket{$_} > 1} keys %key_bucket;
print "Method 1:\n";
print "$_\n" for @duplicates;
# Method 2
# Create a list of unique keys, then check how many hashes each key appears in
print "Method 2:\n";
my %unique = map {$_ => 1} keys %hash1, keys %hash2, keys %hash3;
for my $key (keys %unique) {
my (@matches) = grep {exists $_->{$key}} \%hash1, \%hash2, \%hash3;
print "$key\n" if @matches > 1;
}
@repeat=common(\%a,\%b,\%c);
sub common
{
my %d;
for my $href(@_)
{
while(my $m=each %$href)
$d{$m}++;
}
}
return grep {$d{$_} ==@_} keys %d
}
in scalar context, each returns the next key of the hash. Why doesn't, then, the assignment "my $m = each %$href" return false if the key is "0"? ie
> perl -wle 'my %a = ( 0 => 1, y => 2, z => 4); while (my $m = each %a) { print $m }'
y
0
z
> perl -wle 'my @a = ( 0 => 1, y => 2, z => 4); while (my $m = pop @a) { print $m }'
4
z
2
y
1
> perl -wle 'my @a = ( 0 => 1, y => 2, z => 4); while (my $m = shift @a) { print $m }'
>
perl -MO=Deparse -wle 'my %a = ( 0 => 1, y => 2, z => 4); while (my $m = each %a) { print $m }'
BEGIN { $^W = 1; }
BEGIN { $/ = "\n"; $\ = "\n"; }
my(%a) = (0, 1, 'y', 2, 'z', 4);
while (defined(my $m = each %a)) {
print $m;
}
It checks for defined as the loop condition, not a true value.
Build a list of references to the hashes. Use map to build a key count. Use grep to find duplicate keys:
use strict;
use warnings;
# The hashes
my %hash1 = (1..6);
my %hash2 = (1..4, 7..10);
my %hash3 = (1, 2, 9..12);
# Build the list of hash references
my @hashList = (\%hash1, \%hash2, \%hash3);
my %keyCount;
# Count the keys
map {$keyCount{$_}++} keys %$_ for @hashList;
# Find duplicates
my @common = sort grep {$keyCount{$_} == @hashList} keys %keyCount;
print "@common";
Prints:
1
perlmonks.org content © perlmonks.org and Anonymous Monk, BrowserUk, GrandFather, Hue-Bond, imp, ivancho, perladdict
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03