[已解决] 怎么改进delete-nth?

(defun delete-nth (index seq) 
  (let ((element (nth index seq))) 
     (if element 
         (delete element seq)
       seq)))
1 个赞

或者你直接找到 nth 位置以后, 先 split , 然后再 Join

(defun delete-nth (n list)
  (append (subseq list 0 (1- n)) (nthcdr n list)))

@casouri 这个怎么样?

就是我说的先分成两半, 再把两个列表粘贴到一起.

2 个赞

这个挺好的 :smile: 主要我想的是destructive的。(今天早上新学的词……)

分两半的思路主要是以后再读好懂一点, 要不是自己的代码隔几个月自己都要看半天.

哈哈哈,的确。每隔几个月看之前的代码像看💩一样

我试了试,好像不太行

(defun nd (n list)
  (let ((end (nthcdr (1+ n) list)))
    (setf (nthcdr n list) nil)
    (nconc list end)))
;=> nd
(setq my-seq '(1 1 1 2 3 4))
;=> (1 1 1 2 3 4)
(nd 0 my-seq)
;=> (1 1 2 3 4)
my-seq
;=> (1 1 1 2 3 4)

我讨厌写 cdr, car, cdar, cadr 这种, 过几天, 每次读代码, 都要根据当前的表达式一层一层的数, 心累. :sweat:

告诉你一个小技巧, google 的时候用 lisp blablabla , 不要用 elisp blabla, lisp 高手相对于 elisp 高手要多很多, 然后很多 lisp 的代码拷贝到 emacs 里面是可以直接运行的. :stuck_out_tongue_closed_eyes:

3 个赞

docstring写好的话,一般用的话也不用非得再看源码了。要是需要改可能就费点劲……

(defun nd (n list)
  (let ((end (nthcdr (1+ n) list)))
    (setf (nthcdr n list) end)
    list))

改了。

这个挺好的,不过destructive的有没有可能?

比如

(setq my-seq '(1 2 3 4))
;=> (1 2 3 4)

(delete-nth 0 my-seq)
;=> (3 4)

my-seq
;=> (2 3 4)

不可能破壞性去除一個列表的头。因為头沒了整个表也沒了。

感觉这么搞有点吃力不讨好,我还是用普通的返回新列表的方法吧

感谢 @manateelazycat @LdBeth :smile:

(defmacro nd (n exp)
  (if (zerop n)
      `(progn
         (pop ,exp)
         ,exp)
    `(progn
       (setf (nthcdr ,n ,exp) (nthcdr ,(1+ n) ,exp))
       ,exp)))
1 个赞

(zerop n) 分支可以省略吧?

pop宏内部用的setq来搞,其实不是严格的destructive吧

(let* ((a '(1 2 3)) (b (cdr a))) (pop a) (eq b a)) ;; t

并不能

爲什麼0不能?

(defmacro nd (n exp)
  (let ((b (gensym)))
    `(let ((,b ,exp))
       (setf (nthcdr ,n ,b) (nthcdr ,(1+ n) ,b))
       ,b)))
(setq foo '(1 2 3 4))
;; -> (1 2 3 4)

(nd 0 foo)
;; ->  (2 3 4)

foo
;; -> (1 2 3 4)

因为

不可能破壞性去除一個列表的头。因為头沒了整个表也沒了。