How can "cons per call" be so different for these two very similar functions?



I've written two functions to compare two lists of string tokens.

The first one finds out which elements are common to both:

(defun atoms-in-common (atoms corpus)
"Given atoms (a list of strings) and corpus (also a list of
strings), return a list of those atoms
common to both."
(remove-if #'null (mapcar #'(lambda (x) (when (member x corpus
:test #'string=) x)) atoms)))

And the second one finds out which elements of the first list are not
present in the second:

(defun atoms-in-variance (atoms corpus)
"Given atoms (a list of strings) and corpus (also a list of
strings), return a list of those atoms
not found in corpus."
(remove-if #'null (mapcar #'(lambda (x) (when (not (member x corpus
:test #'string=)) x)) atoms)))

Logically, both are fine.

But when I ran them under the "Metering System" utility, I got some
dramatic differences in "cons per call":
Cons
% % Per
Total Total
Function Time Cons Calls Sec/Call Call
Time Cons
-----------------------------------------------------------------------------------------
ATOMS-IN-COMMON: 12.87 0.21 960 0.000406 116
0.390 111192
ATOMS-IN-VARIANCE: 9.57 0.16 12 0.024167 7131
0.290 85568

Though both (atoms-in-common) and (atoms-in-variance) were not always
called together, when they were (12 times in the above run), the same
two lists were sent to both (atoms-in-common) and (atoms-in-variance),
in that sequence.

So why such a big difference -- 116 cons per call for (atoms-in-common)
versus 7,131 for (atoms-in-variance)?

Does that single (not) statement in (atoms-in-variance) make such an
inpact?

Or can either function be re-written more efficiently?

.



Relevant Pages