Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove array elements equal to some element in a second array in perl

Tags:

perl

Just wonder if I am given two arrays, A and B, how to remove/delete those elements in A that can also be found in B? What is the most efficient way of doing this?

And also, as a special case, if B is the resulting array after grep on A, how to do this? Of course, in this case, we can do a grep on the negated condition. But is there something like taking a complement of an array with respect to another in perl?

Thank you.

like image 953
Qiang Li Avatar asked Sep 22 '11 22:09

Qiang Li


3 Answers

Any time you are thinking of found in you are probably looking for a hash. In this case, you would create a hash of your B values. Then you would grep A, checking the hash for each element.

my @A = 1..9;
my @B = (2, 4, 6, 8);
my %B = map {$_ => 1} @B;

say join ' ' => grep {not $B{$_}} @A; # 1 3 5 7 9

As you can see, perl is not normally maintaining any sort of found in table by itself, so you have to provide one. The above code could easily be wrapped into a function, but for efficiency, it is best done inline.

like image 54
Eric Strom Avatar answered Oct 05 '22 10:10

Eric Strom


Have a look at the none, all, part, notall methods available via List::MoreUtils. You can perform pretty much any set operation using the methods available in this module.

There's a good tutorial available at Perl Training Australia

like image 43
RET Avatar answered Oct 05 '22 09:10

RET


If you ask for most efficient way:

my @A = 1..9;
my @B = (2, 4, 6, 8);

my %x;
@x{@B} = ();
my @AminusB = grep !exists $x{$_}, @A;

But you will notice difference between mine and Eric Strom's solution only for bigger inputs.

You can find handy this functional approach:

sub complementer {
  my %x;
  @x{@_} = ();
  return sub { grep !exists $x{$_}, @_ };
}

my $c = complementer(2, 4, 6, 8);

print join(',', $c->(@$_)), "\n" for [1..9], [2..10], ...;

# you can use it directly of course
print join(' ', complementer(qw(a c e g))->('a'..'h')), "\n";
like image 35
Hynek -Pichi- Vychodil Avatar answered Oct 05 '22 10:10

Hynek -Pichi- Vychodil