Prev: intro to chinese punctuation for english speakers (with computing & linguistic perspective)
Next: [ANN] Call for Participation for 2010 Workshop on Scheme and Functional Programming
From: Haris Bogdanović on 7 Aug 2010 12:41 Hi. Is there a function like nth that also removes nth element from the list ? Thanks
From: Tamas K Papp on 7 Aug 2010 13:09 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 7 Aug 2010 14:38 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 7 Aug 2010 15:24
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/ |