The best i could figure out is :
Code: Select all
(progn
(push (nth n l) out)
(setf l (delete (nth n l) l))
Is there a better way to do that ?
Code: Select all
(progn
(push (nth n l) out)
(setf l (delete (nth n l) l))
Code: Select all
(if (zerop n)
(progn (push (car l) out)
(setf l (cdr l)))
(let ((prevcdr (nthcdr (- n 1) l)))
(push (cadr prevcdr) out)
(setf (cdr prevcdr) (cddr prevcdr))))
Code: Select all
(progn
(push (nth n l) out)
(setf l (nconc (subseq l 0 n) (nthcdr (1+ n) l))))
Good point ! In my case this was not an issue, i forgot to mention that all the elements of l are different. But it is sure something to be aware of.gugamilare wrote:
I'd say that the biggest problem with that code is not preformance, but it will delete multiple copies of the same element if it is found. If that is what you want, use let to store the nth value instead of computing it twice.
Haven't you learned Lisp yet?vernonsolo wrote:Thanks Gugamilare, the first one look like what i was looking for.
I was hoping there was a standard function that could help in this kind of case. Something like "pop" but which can work in the middle of a list. But now i realize that the "one way" nature of the lists makes this difficult to do.
Code: Select all
(defmacro pop-nth (n l)
(with-gensyms (nvar lvar ncdr)
`(let* ((,nvar ,n)
(,lvar ,l)
(,nthcdr (nthcdr ,nvar ,lvar)))
(prog1 (car ,nthcdr)
(setf ,l (nconc (subseq ,lvar 0 ,nvar)
(cdr ,nthcdr)))))))
Code: Select all
(defmacro npop-nth (n l)
(with-gensyms (nvar lvar prevcdr)
`(let ((,nvar ,n)
(,lvar ,l))
(if (zerop ,nvar)
(prog1 (car ,lvar)
(setf ,l (cdr ,lvar)))
(let ((,prevcdr (nthcdr (- ,nvar 1) ,varl)))
(prog1 (cadr ,prevcdr)
(setf (cdr ,prevcdr) (cddr ,prevcdr))))))))
I just started few days agogugamilare wrote: Haven't you learned Lisp yet?![]()
Code: Select all
(defmacro pop-nth (n l)
(let ((nvar (gensym)) (lvar (gensym)) (ncdr (gensym)))
`(let* ((,nvar ,n)
(,lvar ,l)
(,ncdr (nthcdr ,nvar ,lvar)))
(prog1 (car ,ncdr)
(setf ,l (nconc (subseq ,lvar 0 ,nvar)
(cdr ,ncdr)))))))
Code: Select all
(push (pop-nth n l) out)
If you try it with bigger lists, the performance gain will be even greatervernonsolo wrote:PS: then i tried the destructive one and gained 20% speed from the original
Code: Select all
(defmacro awhen (test &rest code)
`(let ((it ,test))
(when it ,@code)))
(defun steal (n list)
(awhen (nthcdr (1- n) list)
(prog1 (cadr it) (rplacd it (cddr it)))))
Code: Select all
(defvar *test-input* '(a b c d e f g))
(steal 1 *test-input*) ;; Returns 'b, *test-output* is now (a c d e f g)
Code: Select all
(defvar *input* '(a b c d e))
(defvar *output* nil)
(defun steal/pop (n)
(if (and *test-input* (zerop n))
(setf *output* (cons (car *input*) *output*)
*input* (cdr *input*))
(and (< n (length *input*)) (push (steal n *input*) *output*))))
Code: Select all
(defvar *new-input* '(sentinal a b c d e))