From: Greg Menke
Subject: Which is more efficient
Date: 
Message-ID: <iuc5np9w.fsf@erols.com>
Hi again,

Is it more efficient to manipulate a list via destructive operators;
rplcad, delete, etc... or non-destructive; append, etc...?

What I think I'm asking is, do non-destructive operators copy the
input list(s) to create the output, or do they gerrymander pointers to
reference the existing list?  I gather some do, but I'm not clear on
when they do (always or under certain circumstances).

For example; if I want to add a new item onto a really big list, is
the following approach a good one?

(setq big-list (append (list 3.14159) big-list)

My tentative conclusion that delete might be better than remove for
getting rid of an item from a list, only because the docs say remove
generates a copy of the list.  Is this correct?


Sorry if I'm not asking the right questions, and thanks for any help.

Gregm
From: Kent M Pitman
Subject: Re: Which is more efficient
Date: 
Message-ID: <sfwvhg5qg9a.fsf@world.std.com>
Greg Menke <······@erols.com> writes:

> Is it more efficient to manipulate a list via destructive operators;
> rplcad, delete, etc... or non-destructive; append, etc...?

Destructive operators use no additional space.  Whether this is most
efficient depends on the circumstance.  (There are cases where copying
improves locality and improves paging behavior, but as a rule it's not
usually something people think about unless metering turns up that
particular issue as a performance bottleneck.)
 
> What I think I'm asking is, do non-destructive operators copy the
> input list(s) to create the output, or do they gerrymander pointers to
> reference the existing list?  I gather some do, but I'm not clear on
> when they do (always or under certain circumstances).

Non-destructive operators generally do not copy more than they have to,
so it's not as bad as you might fear. For example, in
 (setq x '(a b c))
 (setq y '(d e f))
 (setq a1 (append x y))
 (setq a2 (append x y))

 (eq a1  x) => nil
 (eq a2  x) => nil
 (eq a1 a2) => nil

 (eq (nthcdr 3 a1) y) => t
 (eq (nthcdr 3 a2) y) => t
 (eq (nthcdr 3 a1) (nthcdr 3 a2)) => t

> For example; if I want to add a new item onto a really big list, is
> the following approach a good one?
> 
> (setq big-list (append (list 3.14159) big-list)

Sort of.  A good working rule is "never use APPEND".  It's useful once
in a while but not often enough to be a weapon of first choice and I
just don't recommend it for novices.  If you see a use of APPEND, you're
probably doing something wrong.

Here, for example, you are consing a list and then throwing it away in
the APPEND, which copies the little list.  You want
 (setq big-list (cons pi big-list))
[Note that pi is a lisp built-in with better precision than you gave it.]
By using APPEND, you are effectively saying:
 (setq big-list (cons (car (cons pi nil)) big-list))
though APPEND has to do more work to even figure this out.  But note the
inner cons and the immediate car to extract its data.
 
> My tentative conclusion that delete might be better than remove for
> getting rid of an item from a list, only because the docs say remove
> generates a copy of the list.  Is this correct?

This depends on whether you own all the copies.  If you're sharing the
list with someone else, you must use remove.  Note that REMOVE might only
copy the part of the list that is needed to do the REMOVE.  Note also
that you can tell REMOVE to stop after it finds the item so it doesn't
keep looking for more farther down the list; see the :count argument.

> Sorry if I'm not asking the right questions, and thanks for any help.

They are good questions.