On 5/11/10 Tue May 11, 2010 1:52 PM, "Harry Putnam" <rea...@newsguy.com> scribbled:
> 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. It is not fair to single out Shawn for help. Just post your question and hope for a response. > %d1h is made up like this > > this is key this is value > $File::Find::name = $_ The use of the equal sign '=' in the above makes it look like you are assigning a value to $File::Find::name. It is better to stick to Perl syntax: $d1h{$File::Find::name} = $_; for example: $d1h{'./dir1/sub/fname'} = 'fname'; > 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 You can use the Unix file command (if you are on Unix) to find the files with a certain name: find dir1 -name README etc. to check the results of your program. Your program below looks fine. I see no obvious defects. You can generate the inverted hashes in the find routines (see below). You can use the inverted hashes only (see below). > #!/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 > my( %inv_d1h, %inv_d2h ); > find sub { > return unless -f; > $d1h{ $File::Find::name } = $_; push( @{$inv_d1h{$_}}, $File::Find::name ); > },$d1; > > find sub { > return unless -f; > $d2h{ $File::Find::name } = $_; push( @{$inv_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"; > } > } > Using only "inverted" hashes (untested): for my $file ( sort keys %inv_d1h ) { if( exists $inv_d2h{$file} ) { print "Duplicate file names found: ", scalar @{$inv_d1h{$file}}, " in $d1 and ", scalar @{$inv_d2h{$file}}, " in $d2\n"; print "\n$d1:\n ", join("\n ",@{inv_d1h{$file}}), "\n"; print "\n$d2:\n ", join("\n ",@{inv_d2h{$file}}), "\n"; } } -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/