Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Q: what idiom for inserting an element in a list

4 views
Skip to first unread message

Robert Strandh

unread,
Aug 10, 2002, 11:32:42 AM8/10/02
to
Hello,

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

Kent M Pitman

unread,
Aug 10, 2002, 1:54:55 PM8/10/02
to
Robert Strandh <str...@labri.u-bordeaux.fr> writes:

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.)]

Tim Moore

unread,
Aug 11, 2002, 1:45:42 AM8/11/02
to
On 10 Aug 2002 17:32:42 +0200, Robert Strandh <str...@labri.u-bordeaux.fr>
wrote:

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

Pascal Bourguignon

unread,
Aug 11, 2002, 4:42:58 AM8/11/02
to

tmo...@sea-tmoore-l.dotcast.com (Tim Moore) writes:

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/
----------------------------------------------------------------------


Robert Strandh

unread,
Aug 11, 2002, 5:30:08 AM8/11/02
to
tmo...@sea-tmoore-l.dotcast.com (Tim Moore) writes:

> 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

Robert Strandh

unread,
Aug 11, 2002, 5:38:00 AM8/11/02
to
Kent M Pitman <pit...@world.std.com> writes:

> 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

Robert Strandh

unread,
Aug 11, 2002, 5:35:12 AM8/11/02
to
Pascal Bourguignon <too.mu...@example.com> writes:

> 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

Joel Ray Holveck

unread,
Aug 11, 2002, 6:18:49 AM8/11/02
to
>> (defun insert-by-position (val list pos)
[snip]

> 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.
[snip]

> Personnaly, I prefer:
> (defun insert-by-position-r (val list pos)
[snip]

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

Hrvoje Niksic

unread,
Aug 11, 2002, 10:17:53 PM8/11/02
to
Robert Strandh <str...@labri.u-bordeaux.fr> writes:

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.

Erik Naggum

unread,
Aug 12, 2002, 2:45:57 AM8/12/02
to
* Hrvoje Niksic <hni...@xemacs.org>

| 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.

Barry Margolin

unread,
Aug 12, 2002, 10:52:51 AM8/12/02
to
In article <32381235...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:
>* Hrvoje Niksic <hni...@xemacs.org>
>| 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 ...)) ...).

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.

0 new messages