[geeks] Programming question.
David Cantrell
david at cantrell.org.uk
Tue Apr 2 09:41:20 CST 2002
On Tue, Apr 02, 2002 at 10:11:10AM -0500, alex j avriette wrote:
> erm, typo:
> > my @missing = map { grep { $_ } @lista } @listb;
> thats not @missing, its @common. for missing, you'd use 'not grep'
Did you actually try that before posting?
Each element of @listb gets mapped in turn to the results of
grep { $_ } @lista. In that, $_ takes in turn each element of @lista, so
you get a list of all the true elements of @lista. So ...
my @a = (1,3,5,7,9);
my @b = (0,1,2,3,4,5,6,7,8,9);
my @common = map { grep { $_ } @a } @b;
gives us ...
@common = (1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9); # all true elements of @a, repeated scalar(@b) times
which unless I'm very much mistaken is not what you intended. You thought
that the value of $_ inside that grep would be each item of @listb in turn,
when it ain't. And even if it were, it would still be hideously inefficient,
as you'd still be comparing each element of @lista to each element of @listb,
which is O(n^2).
Your bug fix doesn't work either. It does exactly the same, then applies a
not to each resulting list. Not only makes sense in scalar context, so
each list is converted to a scalar, then notted. Those resulting scalars
are then made into a list. Which with my test data, returned a very nice -
but unwanted - list of false values. And is still of order O(n^2).
My solution not only gives the right result, but is as near as damnit O(n).
I suppose it could be contracted somewhat:
my %a = map { ($_, 1) } @a;
@c = grep { !defined $a{$_} } @b; # or something like that
Which is slightly more efficient (but not much) and, IMO, harder to read.
--
Grand Inquisitor Reverend David Cantrell | http://www.cantrell.org.uk/david
This is nice. Any idea what body-part it is?
More information about the geeks
mailing list