2012-05-17 58 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))) 
) 
) 
相關問題