返回列表没有常见的lisp中的最后一个元素

时间:2012-05-17 13:18:47

标签: list common-lisp

我编写了我的傻功能,它返回一个没有普通lisp中最后一个元素的列表。这个问题还有更优雅的解决方案吗?

这是我的代码:

(defun list-without-last (l)
  (if (> (length (rest l)) 0)
      (append (list (first l)) (list-without-last (rest l)))
      nil))

6 个答案:

答案 0 :(得分:10)

简短而简单,就像Lisp一样。 这是神奇的东西:

(defun without-last(l) (reverse (cdr (reverse l))) )

答案 1 :(得分:8)

您的功能有两个问题:

  • 你正在使用LENGTH。 LENGTH必须扫描整个列表。

  • 您正在使用APPEND。尝试使用CONS。 CONS更简单。

Common Lisp也已经提供了这个功能。它被称为BUTLAST。

在实际代码中,我们也不会使用递归。堆栈大小将限制我们可以处理的列表的长度。

使用LOOP宏的迭代版本:

CL-USER> (defun my-butlast (list)
           (loop for l on list
                 while (rest l)
                 collect (first l)))
MY-BUTLAST                                                                                                                                      
CL-USER> (compile 'my-butlast)
MY-BUTLAST                                                                                                                                      
NIL                                                                                                                                             
NIL                                                                                                                                             
CL-USER> (my-butlast '(1 2 3 4 5))
(1 2 3 4)                                                                                                                                       
CL-USER> (my-butlast '(1))
NIL                                                                                                                                             
CL-USER> (my-butlast '(1 2))
(1)                                                                                                                                             

答案 2 :(得分:1)

有时您可能会发现自己需要修改列表而不是复制,在这种情况下这可能很方便:

(defun butlast! (x)
  (do ((y x (cdr y)))
      ((null (cddr y))
       (and (rplacd y nil) (return x)))))

答案 3 :(得分:0)

正如上面提到的Rainer Joswig,你应该使用常见的lisp内置函数butlast

但是,如果你仍然想看看有效的递归版本会是什么样子:

(defun butlast2 (list)
  (labels ((butlast2-worker (list result)
             (if (null list)
                 (nreverse result)
                 (let ((element (first list))
                       (rest (rest list)))
                   (if (null rest)
                       (nreverse result)
                       (butlast2-worker rest (cons element result)))))))
    (butlast2-worker list ())))

只要您的lisp实现支持尾调用优化,就会将其转换为循环。诀窍在于,每当调用butlast2-worker时,其结果将直接返回,这意味着您不需要跟踪函数先前调用的参数/内部变量。这最后意味着您不需要像通常用于递归函数那样继续填充调用堆栈。

看看Rainer Joswig的定义,你可以看到尺寸的巨大差异。看看loop的力量,并学会尽可能明智地使用它(或更好:使用iterate http://common-lisp.net/project/iterate/)。

答案 4 :(得分:0)

怎么样:

(defun butlast2 (L)
  (if (null (rest L))
    nil
    (cons (first L) (butlast2 (rest L)))
  )
)

答案 5 :(得分:0)

(defun remove-last (lst)
  (do ((l lst (rest l))
       (res '()))
      ((null (rest l)) (nreverse res))
    (push (first l) res)))