这是您的函数,并带有一些注释:
(defun r-count-equal-elem (alist)
(cond
((NULL alist) nil)
;; the two tests below are not necessary in my opinion,
;; the fact that the list may contain NIL elements should
;; be a separate problem, as a first draft you can avoid it
((NULL (car alist)) nil)
((NULL (cadr alist)) nil)
;; what you should be testing is if the cddr is NULL, this would
;; tell you that there is only one remaining element in the list.
((equal (car alist) (cadr alist))
;; you cons the count with a recursive result computed just
;; one place after the current one, but if you have a repetition of
;; N times value V, the recursive count will contain N-1 repetitions
;; of V, etc. you have to advance in the list by N for the recursive
;; case
(cons (count-until-dif alist) (r-count-equal-elem (cdr alist)))
)
;; this looks like a corner case that could be merged
;; with the general case above.
(t (cons 1 (r-count-equal-elem (cdr alist)) )
) ) )
另外,辅助函数效率有点低:
(defun count-until-dif (alist)
;; each time you call count-until-dif you compute the length
;; of the linked list, which needs to traverse the whole list.
;; you generally do not need to know the length, you need to know
;; if there is a next element or not to guard your iteration.
(1+ (loop for i from 0 to (- (length alist) 2)
while (equal (nth i alist) (nth (1+ i) alist))
sum 1)))
我建议编写一个函数 occur-rec,如下所示:
(defun occur-rec (list last counter result)
(if (null list)
....
(destructuring-bind (head . tail) list
(if (equal head last)
(occur-rec ... ... ... ...)
(occur-rec ... ... ... ...)))))
函数最初使用输入列表调用,last 看到的值绑定到 nil,当前 counter 设置为零,result 是 nil。
该函数的目的是通过递归调用occur-rec 将结果的逆向构建到result 中。 last 参数表示哪个是最后一个值,counter 是最后一个值的出现次数。
注意:
- 当你调用
occur-rec时,它会返回你想要返回的反向列表
- 反转后的第一项总是为零,所以你需要丢弃它。