反向LISP列表到位

时间:2013-04-18 07:32:12

标签: lisp

我想编写一个反转列表元素的函数,但它应该就位(也就是说,不要创建一个新的反转列表)。

类似的东西:

>> (setq l ' (a b c d))
((a b c d)
>> (rev l)
(d c b a)
>> l
(d c b a)

我应该遵循哪些标志来实现这一目标?

2 个答案:

答案 0 :(得分:8)

查看nreverse,它会修改列表(请参阅HyperSpec)。

根据评论,请注意@Barmar所做的评论以及规范中的这一点:

  

对于nreverse,序列可能会被破坏并重新用于生成结果。结果可能与序列相同,也可能不同。具体来说,当sequence是一个列表时,nreverse允许设置任何属于序列列表结构的cons的任何部分,car或cdr。

答案 1 :(得分:1)

实现这一点并不困难(忽略故障情况)。关键是使用(setf cdr)重用给定的cons单元格,而不是丢失对先前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))))

[编辑]正如评论中所提到的,要真正就地做到这一点(并且没有考虑到):

(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)
相关问题