问题
I have two arrays, @names
and @employees
, that are filled with strings that represent names. @names
is 2 dimentional, holding references to anonymous arrays, but the location of the data we care about is at @names[i][0]
. I want to loop through @names
and find which names are not in @employees
.
At first I thought that looping through @names
backwards, comparing it to @employees
and deleting any matches from @names
would work, but I run into some errors. Here's what I have:
for my $i (reverse(0 .. $#names)) {
foreach my $employee (@employees) {
if ($names[$i][0] eq $employee) { # line 67
splice(@names, $i, 1);
}
}
}
I run into this error:
Use of uninitialized value in string eq at script.pl line 67, line 2.
The strings are all defined in the array. So I'm guessing that this is caused from me deleting elements in the array while I am looping through it, but I thought that looping through the array backwards would prevent an issue like this from happening.
So where am I going wrong in my loop? Also, I've been really struggling with this loop and that hints to me that something is wrong with my entire thought process. Is there a better method to do this?
回答1:
There's no reason to explicitly loop here. You want to filter names: that's a grep
. You want to check membership: that could be done by a grep
too.
@names = grep {my $name = $$_[0]; not grep $_ eq $name, @employees} @names;
The repeated scanning of the inner array isn't particularly efficient; it can be avoid by pre-populating a set (really a hash) ahead of time.
my %employees = map +($_ => 1), @employees;
@names = grep !$employees{$$_[0]}, @names;
回答2:
Without providing code, what I would do is return a new list of @names. For each name in @names, check if it is in @employees, if not add it to your new list of names.
来源:https://stackoverflow.com/questions/11021693/comparing-two-arrays-removing-items-that-match