I am looking for an idiom for inserting an element (let's say
destructively) at a certain position in a list. Even better, to
splice in a list at a certain position in an other list.
For instance:
* (setf *l* (list 1 2 3 4 5 6 7))
(1 2 3 4 5 6 7)
* (insert-by-position 'a *l* 3)
(1 2 3 A 4 5 6 7)
* *l*
(1 2 3 A 4 5 6 7)
*
Is there an existing idiom that I should use?
--
Robert Strandh
Don't look for idioms.
Make functions.
If you later find your function can be implemented more efficiently, do so
centrally. But don't make clever use of some idiomatic thing to avoid writing
a function with a useful name.
[Incidentally, don't expect that insertion can work by side-effect.
Insertion at position 0 will not be able to. Always do
(setq *l* (insert-by-position 'a *l* 3))
and make sure INSERT-BY-POSITION returns the right value to make this work.
(Although you might want to check out DEFINE-MODIFY-MACRO if you want a
macro interface.)]
Idiomatic or not, here's what I'd do:
(defun insert-by-position (val list pos)
(if (zerop pos)
(cons val list)
(let ((old-tail (nthcdr (1- pos) list)))
(setf (cdr old-tail) (cons val (cdr old-tail)))
list)))
Tim
Which is not very regular:
- (insert-by-position 'A '(1 2 3) 2) won't work generaly (you
can't change the cdr of a literal list such as '(1 2 3)).
- (insert-by-position 'A *l* 0) does not change *l* while
(insert-by-position 'A *l* 1) does. This is quite gratuitous.
Personnaly, I prefer:
(defun insert-by-position-r (val list pos)
(if (= pos 0)
(cons val list)
(cons (car list) (insert-by-position val (cdr list) (1- pos))))
);;insert-by-position
To be used as: (setq new-list (insert-by-position-r (val old-list pos)))
Otherwise, a macro is in order, to handle the case val=0.
--
__Pascal_Bourguignon__ http://www.informatimago.com/
----------------------------------------------------------------------
> Idiomatic or not, here's what I'd do:
>
> (defun insert-by-position (val list pos)
> (if (zerop pos)
> (cons val list)
> (let ((old-tail (nthcdr (1- pos) list)))
> (setf (cdr old-tail) (cons val (cdr old-tail)))
> list)))
OK, that's very close to the one I finally settled on. Though, I used
`push' instead of `setf'.
Thanks,
--
Robert Strandh
> Don't look for idioms.
>
> Make functions.
I was thinking of doing both. Writing a function that uses the
idiom.
> If you later find your function can be implemented more efficiently, do so
> centrally. But don't make clever use of some idiomatic thing to avoid writing
> a function with a useful name.
Sure.
> [Incidentally, don't expect that insertion can work by side-effect.
> Insertion at position 0 will not be able to. Always do
> (setq *l* (insert-by-position 'a *l* 3))
> and make sure INSERT-BY-POSITION returns the right value to make this work.
Yes, I actually knew that. Thanks.
--
Robert Strandh
> tmo...@sea-tmoore-l.dotcast.com (Tim Moore) writes:
>
> > (defun insert-by-position (val list pos)
> > (if (zerop pos)
> > (cons val list)
> > (let ((old-tail (nthcdr (1- pos) list)))
> > (setf (cdr old-tail) (cons val (cdr old-tail)))
> > list)))
> >
> > Tim
>
> Which is not very regular:
>
> - (insert-by-position 'A '(1 2 3) 2) won't work generaly (you
> can't change the cdr of a literal list such as '(1 2 3)).
>
> - (insert-by-position 'A *l* 0) does not change *l* while
> (insert-by-position 'A *l* 1) does. This is quite gratuitous.
Tim's solution is `destructive' (which means exactly that you can't
change literals and that it has this `gratuitous' behavior), which is
what I asked for.
--
Robert Strandh
The situation is no different with SORT, or any other destructive
function.
However, we now have an implementation of both INSERT-BY-POSITION and
NINSERT-BY-POSITION (renamed for regularity with most other CL
destructive functions), and the user can use whichever he finds most
appropriate-- remembering all the normal caveats associated with
destructive functions.
joelh
Hardly idiomatic, but my first impulse was to try something like this:
(push 'a (nthcdr 3 *l*))
But Common Lisp doesn't seem to define a SETF method for NTHCDR. I
wonder why? Emacs's `cl.el' defines it, and this example works there.
You would of course use (setf (cdr (nthcdr ...)) ...).
--
Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
Except that doesn't work for the 0 case. If SETF of NTHCDR were defined,
it could expand (setf (nthcdr n l) x) into:
(if (zerop n)
(setf l x)
(setf (cdr (nthcdr (1- n))) x))
(with appropriate stuff to fix order of evaluation and prevent multiple
evaluation, of course), rather than requiring the user to special case 0.
--
Barry Margolin, bar...@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.