Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lisp: Elegant way to strip trailing nil's from a list? (Review)

I want to write a function that removes trailing nil's from a list. I first tried to write it elegantly with recursion, but ended up like this:

(defun strip-tail (lst)
  (let ((last-item-pos (position-if-not #'null lst :from-end t)))
    (if last-item-pos
      (subseq lst 0 (1+ last-item-pos)))))

; Test cases.
(assert (eq nil (strip-tail nil)))
(assert (eq nil (strip-tail '(nil))))
(assert (equal '(a b) (strip-tail '(a b nil nil))))
(assert (equal '(a nil b) (strip-tail '(a nil b nil))))
(assert (equal '(a b) (strip-tail '(a b))))

It's arguably clear, but I'm not convinced. Is there a more lispy way to do it?

like image 616
Johan Kotlinski Avatar asked Feb 28 '23 13:02

Johan Kotlinski


2 Answers

Well, a version would be:

  1. reverse the list
  2. remove leading nils
  3. reverse the list

The code:

(defun list-right-trim (list &optional item)
  (setf list (reverse list))
  (loop for e in list while (eq item e) do (pop list))
  (reverse list))

Here is another variant:

  1. iterate over the list and note the position of the first nil which is only followed by nils
  2. return the sub-sequence

the code:

(defun list-right-trim (list &aux (p nil))
  (loop for i from 0 and e in list
    when (and (null p) (null e)) 
    do (setf p i)
    else when (and p e) do (setf p nil))
  (if p (subseq list 0 p) list))
like image 174
Rainer Joswig Avatar answered Mar 31 '23 19:03

Rainer Joswig


(defun strip-tail (ls)
    (labels ((strip-car (l)
                  (cond ((null l)       nil)
                        ((null (car l)) (strip-car (cdr l)))
                        (t              l))))
        (reverse (strip-car (reverse ls)))))

Sample run (against your test cases):

[1]> (assert (eq nil (strip-tail nil)))
NIL
[2]> (assert (eq nil (strip-tail '(nil)))) ;'
NIL
[3]> (assert (equal '(a b) (strip-tail '(a b nil nil))))
NIL
[4]> (assert (equal '(a nil b) (strip-tail '(a nil b nil))))
NIL
[5]> (assert (equal '(a b) (strip-tail '(a b))))
NIL
[6]> 
like image 29
dsm Avatar answered Mar 31 '23 19:03

dsm