From: Haris Bogdanović on
Hi.

Is there a function like nth that also removes nth
element from the list ?

Thanks
From: Tamas K Papp on
On Sat, 07 Aug 2010 18:41:14 +0200, Haris Bogdanović wrote:

> Hi.
>
> Is there a function like nth that also removes nth element from the list

Not that I know of, but it is very easy to write:

(defun remove-nth (n list)
"Remove nth element from list (counting from 0). Non-destructive, may share
structure in the tail. Returns the removed element as the second value."
(loop
with elements := nil
for (head . tail) :on list
for index :from 0
do (if (= index n)
(return-from remove-nth (values (nreconc elements tail) head))
(push head elements)))
list)

A destructive version (untested):

(defun delete-nth (n list)
(let* ((tail (nthcdr (1- n) list))
(elt (cadr tail)))
(setf (cdr tail) (cddr tail))
(values list elt)))

Hope this helps,

Tamas
From: Tamas K Papp on
On Sat, 07 Aug 2010 17:09:56 +0000, Tamas K Papp wrote:

> On Sat, 07 Aug 2010 18:41:14 +0200, Haris Bogdanović wrote:
>
>> Hi.
>>
>> Is there a function like nth that also removes nth element from the
>> list
>
> Not that I know of, but it is very easy to write:
>
> (defun remove-nth (n list)
> "Remove nth element from list (counting from 0). Non-destructive, may
> share
> structure in the tail. Returns the removed element as the second
> value."
> (loop
> with elements := nil
> for (head . tail) :on list
> for index :from 0
> do (if (= index n)
> (return-from remove-nth (values (nreconc elements tail)
> head)) (push head elements)))
> list)
>
> A destructive version (untested):
>
> (defun delete-nth (n list)
> (let* ((tail (nthcdr (1- n) list))
> (elt (cadr tail)))
> (setf (cdr tail) (cddr tail))
> (values list elt)))

I realized that this doesn't work for n=0. Corrected version:

(defun delete-nth (n list)
(if (zerop n)
(values (cdr list) (car list))
(let* ((tail (nthcdr (1- n) list))
(elt (cadr tail)))
(setf (cdr tail) (cddr tail))
(values list elt))))

Tamas
From: Pascal J. Bourguignon on
Haris Bogdanović <fbogdanovic(a)xnet.hr> writes:
> Is there a function like nth that also removes nth
> element from the list ?

Basically, just write what you say!

(pop (cdr (nthcdr (1- n) list)))

On the other hand, if it doesn't exist it's because as you can see, it
has problems.

What should be done when n is zero?

You cannot write a function that modifies the place of its argument.

So either you want a function, or you want to remove an element from
the list at a place? If you want a function, you could do:

(setf list (delete-if (constantly t) list :start n :end (1+ n)))

If you want to remove an element from the list at a place, you could
write a macro:

CL-USER> (defmacro deletenth (n list &environment env)
(let ((vn (gensym)))
(multiple-value-bind (vars vals stores writer reader)
(get-setf-expansion list env)
`(let ((,vn ,n)
,@(mapcar (function list) vars vals)
(,(car stores) ,reader))
(if (zerop ,vn)
(prog1 (pop ,(car stores))
,writer)
(pop (cdr (nthcdr (1- ,vn) ,(car stores)))))))))

DELETENTH
CL-USER> (let ((l1 (list 1 2 3 4))
(l2 (list 1 2 3 4)))
(print (deletenth 0 l1))
(print (deletenth 2 l2))
(values l1 l2))

prints:
1
3
returns:
(2 3 4)
(1 2 4)



CL-USER> (defun deletenth* (n list)
(setf list (delete-if (constantly t) list :start n :end (1+ n))))
DELETENTH*
CL-USER> (let ((l1 (list 1 2 3 4))
(l2 (list 1 2 3 4)))
(setf l1 (deletenth* 0 l1))
(setf l2 (deletenth* 2 l2))
(values l1 l2))

(2 3 4)
(1 2 4)




--
__Pascal Bourguignon__ http://www.informatimago.com/