lisp - 计算相等的元素
问题描述
我有这个清单:
(2 2 2 2 3 4 4 5 5 5 6 7 7 7 8 8)
并想返回重复次数。结果应该是这样的:
(4 1 2 3 1 3 2)
我尝试了一种递归方法,但没有成功。我不确定这是正确的方法。
首先,我创建了一个函数来计算元素相等时的计数:
(defun count-until-dif (alist)
(1+ (loop for i from 0 to (- (length alist) 2)
while (equal (nth i alist) (nth (1+ i) alist))
sum 1)))
然后是递归函数(不工作!):
(defun r-count-equal-elem (alist)
(cond
((NULL alist) nil)
((NULL (car alist)) nil)
((NULL (cadr alist)) nil)
((equal (car alist) (cadr alist))
(cons (count-until-dif alist) (r-count-equal-elem (cdr alist)))
)
(t (cons 1 (r-count-equal-elem (cdr alist)) )
) ) )
解决方案
这是您的函数,并带有一些注释:
(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
。
该函数的目的是result
通过递归调用occur-rec
. 该last
参数指示哪个是最后看到的值,并且counter
是最后一个值的出现次数。
注意:
- 当您调用时
occur-rec
,它会返回您想要返回的反向列表 - 反转后的第一项将始终为零,因此您需要将其丢弃。
推荐阅读
- node.js - mongo 文档中的对象在 EJS 中显示未定义
- excel - Excel宏在“,”之后剪切并粘贴到另一个单元格
- python - _tkinter.TclError:不能使用“pyimage1”作为iconphoto:不是照片图像
- c++11 - typeid vs std::is_same vs if constexpr
- node.js - DigestUtils 到 Crypto
- android - 带有 SelectClasses 的 Junit5 testSuite 在 android 单元测试中不起作用
- python - 无法弄清楚这个错误来自哪里
- gmail - Gmail API:如何将草稿移至收件箱,就像我们在 Gmail UI 中所做的那样
- serverless-framework - RequestError:证书链中的自签名证书(无服务器)
- javascript - 如何操作 onchange ajax?