我想編寫一個反轉列表元素的函數,但它應該發生(即不要創建新的反轉列表)。反向LISP列表
喜歡的東西:
>> (setq l ' (a b c d))
((a b c d)
>> (rev l)
(d c b a)
>> l
(d c b a)
我應該遵循什麼標誌來實現這一目標?
我想編寫一個反轉列表元素的函數,但它應該發生(即不要創建新的反轉列表)。反向LISP列表
喜歡的東西:
>> (setq l ' (a b c d))
((a b c d)
>> (rev l)
(d c b a)
>> l
(d c b a)
我應該遵循什麼標誌來實現這一目標?
實現這一點並不難(忽略故障情況)。關鍵是使用(setf cdr)
來重新使用給定的缺陷單元,而不是丟失對先前的cdr的引用。
(defun nreverse2 (list)
(recurse reving ((list list) (rslt '()))
(if (not (consp list))
rslt
(let ((rest (cdr list)))
(setf (cdr list) rslt)
(reving rest list)))))
(defmacro recurse (name args &rest body)
`(labels ((,name ,(mapcar #'car args) ,@body))
(,name ,@(mapcar #'cadr args))))
[編輯]作爲在留言中提到,要做到這一點真正就地(和W/O方面consing):
(defun reverse-in-place (l)
(let ((result l))
(recurse reving ((l l) (r (reverse l))
(cond ((not (consp l)) result)
(else (setf (car l) (car r))
(reving (cdr l) (cdr r)))))))
> (defvar l '(1 2 3))
> (reverse-in-place l))
(3 2 1)
> l
(3 2 1)
回收利弊細胞(所以它適當地稱爲'nreverse2'(n代表無需承擔)),但它不會顛倒列表_in place_。原始列表頭部的缺點不是倒排列表的頭部。例如,(let((l(list 1 2 3)))(nreverse2 l)l)'產生'(1)'。 – 2013-04-19 17:09:44