Return list without a common lisp element

I wrote my stupid function that returns a list without the last element in general lisp. Is there a more elegant solution to this problem?

Here is my code:

(defun list-without-last (l) (if (> (length (rest l)) 0) (append (list (first l)) (list-without-last (rest l))) nil)) 
+4
source share
6 answers

Your function has two problems:

  • you are using length. LENGTH should scan the entire list.

  • you are using APPEND. Try using CONS. CONS is easier.

Generic Lisp also already provides this feature. It is called BUTLAST.

In real code, we will not use recursion either. The size of the stack would limit the length of the lists that we can process.

Iterative version using the LOOP macro:

 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) 
+8
source

Shorter and simpler, like Lisp. Here is the magic stuff:

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

+9
source

Sometimes you may need to change the list in place, rather than making a copy, in which case it may be convenient:

 (defun butlast! (x) (do ((yx (cdr y))) ((null (cddr y)) (and (rplacd y nil) (return x))))) 
+1
source

As Rainer Joswig said, you should use the generic built-in function lisp butlast .

But, if you still want to see what an efficient recursive version looks like:

 (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 ()))) 

As long as your lisp implementation supports tail call optimization, it will be converted to a loop. The trick is that whenever butlast2-worker is called, its result will be returned directly, which means you do not need to track the arguments / internal variables from previous function calls. The latter means that you do not need to populate the call stack, as usual, for a recursive function.

Looking at the definition of Rainer Joslig, you can see a huge difference in size. Here is the power of the loop and learn to use it wisely whenever you can (or better: use iterate http://common-lisp.net/project/iterate/ ).

0
source

What about:

 (defun butlast2 (L) (if (null (rest L)) nil (cons (first L) (butlast2 (rest L))) ) ) 
0
source
 (defun remove-last (lst) (do ((l lst (rest l)) (res '())) ((null (rest l)) (nreverse res)) (push (first l) res))) 
0
source

Source: https://habr.com/ru/post/1412981/


All Articles