Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re: Re: Re: Re: Re: List::Compare

by tachyon (Chancellor)
on Mar 25, 2004 at 23:36 UTC ( #339908=note: print w/replies, xml ) Need Help??


in reply to Re: Re: Re: Re: List::Compare
in thread List::Compare

Am I missing something or is List::Compare in your context giving you nothing that this code does not? This is probably faster and will use less memory as well.

my @ary1 = ( 1..10 ); my @ary2 = ( 5..15 ); my %h; $h{$_}++ for ( @ary1, @ary2 ); unique( "Only in ary1", \@ary1, \%h ); unique( "Only in ary2", \@ary2, \%h ); common( "Common to ary1 and ary2", \%h ); sub unique { my ( $text, $ary, $hash ) = @_; print $text, $/; do{ print "$_\n" unless $hash->{$_} == 2} for @$ary; } sub common { my ( $text, $hash ) = @_; print $text, $/; do{ print "$_\n" if $hash->{$_} == 2} for keys %$hash }

cheers

tachyon

Replies are listed 'Best First'.
Re: alternative to List::Compare
by graff (Chancellor) on Mar 26, 2004 at 04:32 UTC
    I agree with your point -- this might be one of those modules that just "objectifies" something that's already pretty simple (so why bother?). Your alternative is a common, simple approach that is bound to be appropriate for the reviewer's main example -- comparing the output of "find" from two different machines -- because there won't be any duplications within a single set. But of course if one element happens to appear more than once in a single list, you get a false report about it being in both lists. This is easy to fix (in fact, fixing it makes the code simpler):
    my @ary1 = qw/1 2 3 4 5 4 6/; my @ary2 = qw/5 6 7 8 7 9 10/; my %h; $h{$_} .= "a" for ( @ary1 ); $h{$_} .= "b" for ( @ary2 ); compare( "Only in ary1", "a\$", \%h ); compare( "Only in ary2", "^b", \%h ); compare( "Common to both", "ab", \%h ); sub compare { my ( $text, $regex, $hash ) = @_; print join "\n", $text, grep { $$hash{$_} =~ /$regex/ } keys %$has +h; print "\n"; }
      graff and tachyon:

      Thanks for the demonstrations. As I mentioned in the review, I'm not entirely comfortable manipulating hashes yet-- and as graff points out succinctly, a small slip can give odd results that are hard to find. (This, BTW, is why I'm spending time at perlmonks-- I'm at the point where I know enough Perl to *really* screw stuff up if I don't understand what I'm doing-- I need to read other people's code as much as I can.)

      And that's another reason why I thought the review was appropriate-- the module author points to his inspiration (much like your code) in the Perl Cookbook, and also to other modules that do similar things.

      This is a great way to learn, while also not making silly mistakes in production code. Does it objectify something simple? Sure-- but it gives me a lot more confidence that my script is working correctly, and also points me to a starting place for when I have to do something more complex later.
      I've always been upfront about the fact that the very first thing List::Compare did was to put an object-oriented wrapper around well-known, Cookbook-style code for list comparisons. The reason I bothered was the Perl virtue of Laziness: I was comparing lists so often, I was tired of re-typing the code. Once I perfected it for my own use, I poked around on CPAN and discovered (to my surprise) that nobody had beaten me to it.

      That being said, I've expanded List::Compare's functionality over the last two years and, in particular, have provided considerable flexibility in its interface. One of its interface's is functional, not object-oriented. So List::Compare is well past the point of merely 'objectifying' something.

      Jim Keenan (author of List::Compare)

      <generalizing>
      Do you need "a\$" and "^b"? That seems rather specific, and doesn't generalize. Perhaps "^a+\$" and "^b+\$" would be a better choice? Then it doesn't matter which one is processed first, or how many there are (e.g., "^c+\$").
      </generalizing>

      BTW, I like the $h{$_} .= "a" idea. To scale it much larger, I'd probably go with a bit vector, something like this:

      my @AoA = ( [1..10], [2..11], [3..12] ); my %h; foreach my $i ( 0..#@AoA ) { vec($h{$_},$i,1) = 1 for @{$AoA[$i]}; }
      Of course, it's a bit more work to get the "only"s and "common"s out %(

      -QM
      --
      Quantum Mechanics: The dreams stuff is made of

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://339908]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (7)
As of 2020-05-30 15:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    If programming languages were movie genres, Perl would be:















    Results (173 votes). Check out past polls.

    Notices?