如何在LISP中创建一个递归函数,用于计算原子在嵌套列表中出现的次数

时间:2016-10-03 14:59:53

标签: recursion lisp common-lisp

刚开始学习lisp,我需要编写一个函数,COUNTER,就像标题中提到的那样。例如,

(COUNTER 'fizz '(fizz (buzz (fizz) (buzz fizz)) fizz))

应该返回4

首先尝试

我写了以下内容

(defun COUNTER (atom list)
  (cond
   ((null list) 0)
   ((equal atom (first list)) (+ 1 (COUNTER atom (rest list))))
   (t (COUNTER atom (rest list)))))

仅计算最高级别的原子(在示例的情况下,我的输出为2)。我需要添加什么才能读取嵌套列表?我知道我应该遍历子列表并对结果求和,但我不确定我应该使用哪个谓词以及我应该放在哪里。我正在考虑

((equal atom (first list)) (+ 1 (COUNTER atom (rest list))))

第二次尝试

我尝试过以下无效

(defun COUNTER (target nest_list)
  (cond ((null nest_list) 0)
    (cond (atom (first nest_list) ((equal target (first nest_list)) (+ 1 (COUNTER target (rest nest_list)))))
      (t (COUNTER target (first nest_list))))
    (t (COUNTER target (rest nest_list)))))

我收到了来自它的编译错误。我的逻辑似乎有道理。我正在测试实体是一个原子还是一个列表,如果是原子,那么看它是否相等并加1,否则重复,如果它是一个列表。我不确定我是否对括号放置做错了,或者我是否允许在这样的cond中使用cond。

2 个答案:

答案 0 :(得分:1)

您可以关闭计数器以避免传递太多参数。 此外,您可能应该像CL函数那样传递自定义test函数。

(defun counter (search tree &key (test #'eql))
  (let ((total 0))
    (labels
        ;; Our tree walker. Both counter and search are accessible
        ;; from the lexical environment, so there is no need to
        ;; pass them as arguments.
        ((walk (tree)
           (cond
             ;; First, see if current element matches the search.
             ;; That allows to search for a list inside a tree.
             ((funcall test tree search) (incf total))

             ;; Otherwise, if this is a cons-cell, recurse in CAR and CDR
             ((consp tree)
              (walk (car tree))
              (walk (cdr tree))))))

      ;; Initiate walk
      (walk tree)

      ;; Return total
      total)))

如果这是一个家庭作业,我不认为这可以满足您的要求(您可能希望提供纯粹的递归功能)。但是,如果您了解上述内容,那么构建一个永远不会改变变量的递归方法应该不难。

供参考:

实施例

(counter '(3 2)
         '(a b (c d 3) (3 2) e f)
         :test #'equalp)
=> 1

(counter 3 '(a b (c d 3) (3 2) e f))
=> 2

答案 1 :(得分:0)

您还需要检查first list本身是原子还是列表。如果它是一个原子,那么你当前的逻辑是正确的;如果它是一个列表,那么需要在此列表中重现。

我删除了有关参数名称的评论,因为它在大多数功能齐全的LISP版本中都不是问题。感谢 coredump 进行更正。

(defun COUNTER (target nest_list)
  (cond ((null nest_list) 0)
    (cond (atom (first nest_list))
      (equal target (first nest_list)) (+ 1 (COUNTER target (rest nest_list))))
      (t (COUNTER target (rest nest_list)))))

现在,在新 cond else 分支中,插入另一个递归:

(COUNTER (target (first nest_list)))

您需要将此(而不是 1 )添加到(rest nest_list)的计数中。这会让你感动吗?我知道我的结构并不小心,但我试图避免为你做这份工作。