Shawn H Corey <shawnhco...@gmail.com> writes:

> Harry Putnam wrote:
>> But, is there an easier way?
>
> Invert both hashes and find the keys in both inverses.

Shawn, hoping to pester you once more about this topic.

first:

  Hashes involved are built like this (Using File::Find nomenclature):

(NOT CODE... Just description)
use File::Find;

%d1h is made up like this

   this is key              this is value
  $File::Find::name      =     $_ 
# ./dir1/sub/fname       =     fname
 
%d2h is made up the same way:
   this is key              this is value
   $File::Find::name      =     $_
# ./dir2/what/sub/fname   =     fname

Also keeping in mind there are many thousands of lines in both hashs. 

There will be many many ways the path part of those names will differ,
and only some will actually match on the ends (the values in hash
terms) like the two above. Many more will be different, but the
objective here is to find those that matches.

I've found after many hours of tinkering and bugging the heck out of
patient posters here, what I think you were trying to tell me in this 
thread.  I wasn't capable yet of understanding it all.  I'm still not
but quite a lot more now has finally wormed into my pea brain.

So cutting to the chase, I try to take advantage of your inversion
code.  It seems to work well, but I'm not confident enough to know
if there are possible hidden gotchas someone with more experience
might see right off the bat.
 
-------        ---------       ---=---       ---------      -------- 
Some selective output first:

  [...]

  d1         ./dir1/etc/images/gnus/exit-summ.xpm
  d2    (1)  ./dir2/etc/images/gnus/exit-summ.xpm

  d1         ./dir1/etc/images/gnus/reply.xpm
  d2    (1)  ./dir2/etc/images/mail/reply.xpm
  d2    (2)  ./dir2/etc/images/gnus/reply.xpm

  d1         ./dir1/etc/images/gnus/README
  d2    (1)  ./dir2/src/m/README
  d2    (2)  ./dir2/etc/e/README
        [...] 
  d2    (47)  ./dir2/doc/lispintro/README                   

  d1         ./dir1/lisp/gnus-util.el
  d2    (1)  ./dir2/lisp/gnus/gnus-util.el

  [...]

------- 8< snip ---------- 8< snip ---------- 8<snip ------- 

#!/usr/local/bin/perl

use strict;
use warnings;
use File::Find;
#use diagnostics;

my %d1h;
my %d2h;
my $d1tag = 'd1';
my $d2tag = 'd2';

## Make sure we are  feed two directory names
( my ( $d1, $d2 ) = @ARGV ) == 2 
    or die "\nUsage: $0 ./dir1 ./dir2\n";

  ## Make sure incoming directory names exist
  for ($d1, $d2 ){
     ( -d ) or die "<$_> cannot be found on the file system";
  }

  ## Build the hashs

  find sub {
      return unless -f;
      $d1h{ $File::Find::name } = $_;
    },$d1;

  find sub {
      return unless -f;
      $d2h{ $File::Find::name } = $_;
    },$d2;

## Invert 1 hash and it needs to be the second one on cmd line
my %inv_d2h = invert( \%d2h );

sub invert {
   my $h = shift @_;
   my %inv = ();

   while( my ( $k, $v ) = each %{ $h } ){
     push @{ $inv{$v} }, $k;
   }
   return %inv;
}

## Could have used `values' of %d1h here for $value (values %d1h) 
## and avoided things like `...@{ $inv_d2h{ $d1h{ $key } } }',
## which would then be     `...@{ $inv_d2h{ $value } }'  but would
## not then have such ready access to the `keys' which are
## needed here too, and will be needed later on (not shown here)
## for now we just print to show how it works.

foreach my $key ( keys %d1h ){
  if(exists $inv_d2h{ $d1h{ $key } }){
     print "  $d1tag         $key\n";

       ## separate counter to keep (my) confusion down
       my $matchcnt = 0;
       for ( @{ $inv_d2h{ $d1h{ $key } } } ) {
           print "  $d2tag    (" . ++$matchcnt .")  $_\n";
       }
       print "\n";
  }              
}




-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to