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.
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.
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
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";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With