计算 lisp 中的出现次数

Count occurrences in lisp

我正在尝试用 lisp 编写代码来计算 lisp 列表中原子的出现次数。 问题是代码适用于除原子 () 之外的所有原子,它显示为 NIL。 代码示例:

(defun flatten (list_) 
    (cond   ((atom list_) (list list_))
            ((null list_) NIL)
            (t (append (flatten (car list_)) (flatten (cdr list_))) )
    )
)

(defun toUniqueList (list_ out) 
    (cond   ((null list_) NIL)
            ((not (member (car list_) out)) (append (list (car list_)) (toUniqueList (cdr list_) (append (list (car list_)) out)) ))
            (t (toUniqueList (cdr list_) out))
    )
)

(defun countOccurences (list_ x) 
    (cond   ((null list_) 0)
            ((eql (car list_) x) (+ (countOccurences (cdr list_) x) 1))
            (t (countOccurences (cdr list_) x))
    )

)

(defun countOccurencesAll (list_) 
    (setq flatList (flatten list_))
    (setq parsed (toUniqueList flatList '()))
    (setq result '())
    (dolist (x parsed)
        (setq result (append result (list (list x (countOccurences flatList x)) ))))
    result
)

(write (countOccurencesAll '(x y z 4.6 (a x) () (5 z x) ())))
; ((X 3) (Y 1) (Z 2) (4.6 1) (A 1) (NIL 5) (5 1))

知道如何显示 () 而不是 NIL 吗?

表达式 nil'nil()'() 都计算为 nil,显示为 nil,除非它是一对中的 cdr,它将关闭列表。例如。 '(() . ()) 的计算结果为 (NIL . NIL),并显示为 (NIL)。你对此无能为力。

那么问题来了,因为 ((a) (()) (c)) 真的是 ((a . nil) . ((nil . nil) . ((c . nil) . nil))) 应该算 nil/() 5 次还是在 nil 时忽略cdr 一对,算作一对吗?

顺便说一句,在未定义的绑定上使用 countOccurencesAll 中的 setq 意味着您的代码受实现的支配。 hyperspec 没有定义它应该如何处理,SBCL 就它如何解释代码发出警告,其他人可能只是选择一种解释。更好的方法是使用 let 来定义绑定。使用散列并遍历列表一次将生成 O(n) 解决方案。