You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在递归循环中正确统计计数?Lisp递归函数计数异常排查

问题描述

我编写了一个用于统计文件中内容出现次数的递归函数,习惯使用format函数输出函数执行结果。以下是我的Lisp代码:

(defun csv-counter (list)
  (let ((counter 0)
        (email (first list)))
    (if (null list)
        nil
        (progn
          (+ 1 (count email list :test #'string=))
          (incf counter)
          (csv-counter (rest list))))
    (format t "count for email ~a is ~a~%" email counter)))

但format函数中的计数器并未累加统计总数,而是每次输出均为1,输出示例如下:

...
count for email fred@test.com is 1
count for email fred@test.com is 1
count for email fred@test.com is 1
... 

请问我哪里出错了?

问题分析与解决方案

你的代码存在三个核心问题:

  • 计数器无法累加:每次递归调用csv-counter时,let都会创建一个全新的counter变量并初始化为0,之后仅执行一次incf counter将其变为1。每个递归层的counter都是独立的局部变量,根本无法实现跨层累加。
  • 无效计数代码:(+ 1 (count email list :test #'string=))这个表达式完全无用——count已经能直接返回email在list中的出现次数,你既没把这个结果赋值给counter,也没做任何其他处理。
  • 重复统计输出:递归遍历每个元素时,会对重复邮箱多次统计并输出,导致同一邮箱的结果被打印多次,而非只输出一次总计数。

修正后的实现

方案1:哈希表统计(高效简洁)

用哈希表一次性统计所有邮箱的出现次数,再统一输出,这是最常用的实现方式:

(defun csv-counter (list)
  (let ((count-table (make-hash-table :test #'equal)))
    ;; 遍历列表,累加每个邮箱的计数
    (dolist (email list)
      (incf (gethash email count-table 0)))
    ;; 遍历哈希表输出结果
    (maphash (lambda (email count)
               (format t "count for email ~a is ~a~%" email count))
             count-table)))

方案2:递归传递统计状态

如果坚持用递归实现,可以通过可选参数传递哈希表,在递归过程中累积计数:

(defun csv-counter-recursive (list &optional (count-table (make-hash-table :test #'equal)))
  (if (null list)
      ;; 列表遍历完成后输出所有统计结果
      (maphash (lambda (email count)
                 (format t "count for email ~a is ~a~%" email count))
               count-table)
      ;; 累加当前邮箱的计数,继续递归
      (progn
        (incf (gethash (first list) count-table 0))
        (csv-counter-recursive (rest list) count-table))))

内容的提问来源于stack exchange,提问作者Vinn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 12:15:27