how can i return the common keys from a hash
Anonymous Monk
created: 2006-08-04 17:40:33
hi monks,
I have 5 hashes,inthese some key values are repeating in all the hashes,how can i list those keys which are occuring in more than one hash.
Re: how can i return the common keys from a hash
created: 2006-08-04 17:52:36

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

Re: how can i return the common keys from a hash
created: 2006-08-04 17:52:51

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

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
Re: how can i return the common keys from a hash
imp
created: 2006-08-04 17:54:03
Here are a two possible ways to find which keys appear in multiple hashes. Neither of these will report how many occurrences, or which hash they appear in - but either would be fairly easy to add.
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;
}

Re: how can i return the common keys from a hash
created: 2006-08-04 18:02:12
If u want to return the common keys from hashes,use the fallowing sub to pass hash ref as arguments to sub.
@repeat=common(\%a,\%b,\%c);
sub common
{
  my %d;
 for my $href(@_)
  {
    while(my $m=each %$href)
     $d{$m}++;
   }
}
 return grep {$d{$_} ==@_} keys %d
}
Re^2: how can i return the common keys from a hash
created: 2006-08-04 21:19:57
I am somewhat puzzled by the following DWIM:

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 }'
>
Re^3: how can i return the common keys from a hash
imp
created: 2006-08-04 21:42:07
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.
Re^4: how can i return the common keys from a hash
created: 2006-08-04 22:07:37
indeed, as that's what you want in 99% of the cases..
I was mostly pointing out that it's neither logical, nor obvious from docs
Re: how can i return the common keys from a hash
created: 2006-08-04 18:52:45

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

DWIM is Perl's answer to Gödel

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