tags:

views:

124

answers:

4

I am new to programming and hence I am stuck on a basic level problem.

Following is code I wrote for comparison. But the result I get does not make sense to me. I would appreciate if someone could tell me what is going wrong.

There are two arrays: @array1 , @array2 of unequal length.

I wish to compare both and list down values not present in @array1.

my %temp = map {$_,$_}@array2;
for (@array1){
next if exists $temp{$_};
open (FILE, ">>/filename") or die "$!";
print FILE "$_\n";
close(FILE);
}
+7  A: 

See the FAQ How do I compute the difference of two arrays? How do I compute the intersection of two arrays?

Adapting the code you posted:

#!/usr/bin/perl

use strict; use warnings;

my @x = 1 .. 10;
my @y = grep { $_ % 2 } @x;

my %lookup = map { $_ => undef } @y;

for my $x ( @x ) {
    next if exists $lookup{$x};
    print "$x\n";
}
Sinan Ünür
I usually do `my %seen; @seen{@y} = (1) x @y;` instead of `map`, but they amount to the same thing.
Ether
@Ether - Because microoptimization is fun, my becnhmarks show that as being slightly faster than `map`. Clever _and_ efficient.
Chris Lutz
I can't resist using hash slices! :)
Ether
+1  A: 

Swap @array1 and @array2 in your code?

David Toso
+5  A: 

If you're doing this for a test, which I assume you are I would highly suggest is_deeply in the newer versions of Test::More

You'll have to update Test::More

cpanp install Test::More

or if you're on perl 5.5

cpan Test::More

Then you'll have use it

use Test::More;
tests => 1
is_deeply ( \@arr1, \@arr2, 'test failed' );

If you're not doing this for testing, but you're doing this for introspective purposes and the arrays are small, I'd suggest using XXX:

cpanp install http://search.cpan.org/CPAN/authors/id/I/IN/INGY/XXX-0.12.tar.gz

Then you'll have use it

use XXX;
YYY [ \@arr1, \@arr2 ];
Evan Carroll
+3  A: 

That's some pretty clever code you've got there. Your code is more or less identical to what the Perl FAQ says. I might be tempted to do this, however:

my %tmp  = map  { $_ => 1 } @array2;
my @diff = grep { not exists $tmp{$_} } @array1;

This gets everything in @array1 that's not in @array2, but avoiding all of those out-of-style looping constructs (yay for functional programming). Though what I'd really do is this:

sub comp (\@\@) {
  my %t = map { $_ => 1 } @{$_[1]};
  return grep { not exists $t{$_} } @{$_[0]};
}

Then you can just do:

my @diff = comp(@array1, @array2); # get items in @array1 not in @array2
@diff = comp(@arraty2, @array1); # vice versa

Or you can go to CPAN. List::Compare::Functional::complement() does what you want, though the syntax is reversed.

Chris Lutz