如何升级Lisp单元素统计函数,实现列表所有元素出现次数统计
解决列表元素批量统计的问题
嘿,你已经搞定了单个元素的统计函数,现在要扩展成一次性统计a、b、c、d所有元素的出现次数对吧?我给你两种方案,按需选择~
方案一:复用现有函数快速实现
既然你已经有了stejem这个单个元素统计的工具,那最直接的方式就是分别调用它统计每个目标元素,再把结果打包成你想要的格式:
; 先保留你已有的单个元素统计函数 (defun stejem (a L) (cond ((null L) 0) ((equal a (car L)) (+ 1 (stejem a (cdr L)))) (t (stejem a (cdr L))))) ; 新增批量统计函数,针对a、b、c、d (defun stejem-vse (L) (list (list 'a (stejem 'a L)) (list 'b (stejem 'b L)) (list 'c (stejem 'c L)) (list 'd (stejem 'd L)))) ; 测试调用 (print (stejem-vse '(a b c b b a c d)))
运行这段代码,输出正好是你期望的:((a 2)(b 3)(c 2)(d 1))。这个方案的优点是简单直接,完全复用你已有的代码,不需要重新理解复杂逻辑;缺点是如果列表很大,每个元素都要遍历一次列表,效率会稍低。
方案二:一次遍历高效统计
如果你的列表可能比较大,更高效的方式是只遍历一次列表,同时完成所有元素的统计。这里用递归+辅助函数的方式实现:
(defun count-all (L) ; 定义辅助函数,用于更新某个元素的计数 (labels ((update-count (item counts) (cond ; 如果计数列表为空,直接添加这个元素的初始计数1 ((null counts) (list (list item 1))) ; 如果找到目标元素,把计数加1 ((equal item (caar counts)) (cons (list item (+ 1 (cadar counts))) (cdr counts))) ; 没找到就继续递归处理剩下的计数 (t (cons (car counts) (update-count item (cdr counts))))))) (cond ((null L) '()) ; 列表为空时返回空 ; 递归处理列表剩余部分,再更新当前元素的计数 (t (update-count (car L) (count-all (cdr L))))))) ; 如果需要严格按照a、b、c、d的顺序输出,再套一层整理函数 (defun count-all-ordered (L) (let ((counts (count-all L))) (list (assoc 'a counts) (assoc 'b counts) (assoc 'c counts) (assoc 'd counts)))) ; 测试调用 (print (count-all-ordered '(a b c b b a c d)))
这个版本只需要遍历一次列表,效率更高。count-all会返回所有元素的统计结果(顺序是元素最后出现的顺序),count-all-ordered则会把结果按a、b、c、d的顺序整理好,输出和你期望的完全一致。
内容的提问来源于stack exchange,提问作者PabloEscobar
相关产品推荐
相关产品推荐

