2012-05-17 61 views
4

我写了我的愚蠢函数,它返回一个没有最后一个元素的普通lisp列表。有没有更好的解决方案来解决这个问题?返回列表中没有最后一个元素的公共lisp

这里是我的代码:

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

回答

7

你的功能有两个问题:

  • 您使用长度

    。 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)                                    
+0

非常感谢butlast,顺便说一句,有什么用追加的问题? – Sergey

+0

'APPEND'必须扫描整个列表,以及复制所有元素。如果您在一个循环中多次调用'APPEND',最终会得到一个函数,它会随着添加更多元素而呈指数级下降。 –

+0

@EliasMårtenson:追加不会复制最后一个列表。 –

1

有时你可能会发现自己需要修改的地方列表,而不是制作副本,在这种情况下,这可能是有用:

(defun butlast! (x) 
    (do ((y x (cdr y))) 
     ((null (cddr y)) 
     (and (rplacd y nil) (return x))))) 
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的力量,并学会如何使用它(或者更好:使用iteratehttp://common-lisp.net/project/iterate/)。

8

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

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

0

什么:

(defun butlast2 (L) 
    (if (null (rest L)) 
    nil 
    (cons (first L) (butlast2 (rest L))) 
) 
) 
相关问题