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

Common Lisp函数问题:如何返回列表中出现n次的所有元素

问题分析与解决方案

你遇到的问题很明确:原函数在找到第一个符合条件的元素后就立刻终止循环返回了,所以没法收集所有出现次数等于nb的元素。

原函数的问题点

看你写的代码:

(defun count-list (lst nb) 
  (loop for x in lst do 
    (if (eq (count x lst) nb) 
        (return x) ) ) )

这里的(return x)是loop里的终止性返回——一旦找到第一个满足(count x lst) = nb的元素,loop就会立刻停止并返回这个元素,后面的元素根本没机会被检查。这就是为什么调用(count-list lst 1)只返回a,而不是所有出现1次的元素。

改进方案:收集所有符合条件的元素

我们需要把“找到第一个就返回”改成“收集所有符合条件的元素”,同时要注意避免重复收集同一个元素(比如原列表里的b出现3次,如果直接循环每个元素收集,会得到(b b b),这显然不是我们要的)。

方案1:先去重再筛选

最直观的方式是先获取列表中的唯一元素,再逐个检查它们的出现次数,符合条件的就收集到结果列表里:

(defun count-list (lst nb)
  (loop for x in (remove-duplicates lst)
        when (= (count x lst) nb)
        collect x))

测试一下:

  • 执行(setq lst '(a b b b c))后,(count-list lst 3)返回(b),符合你的需求;
  • (count-list lst 1)返回(a c)(这里纠正一下你的笔误:原列表里b出现3次,所以出现1次的是a和c哦)。

方案2:跟踪已处理元素(避免去重函数的依赖)

如果你不想用remove-duplicates,可以自己维护一个“已处理元素”的列表,确保每个元素只被检查一次:

(defun count-list (lst nb)
  (let ((seen nil))
    (loop for x in lst
          unless (member x seen)
            do (push x seen)
          when (= (count x lst) nb)
            collect x)))

这个逻辑和方案1本质一样,只是手动跟踪已处理的元素,避免重复检查。

关键知识点

  • loop的return子句是立即终止循环并返回值,适合找单个元素的场景;
  • loop的collect子句会把符合条件的元素依次收集到一个列表里,最后返回这个列表,适合需要多个结果的场景;
  • 一定要去重,否则同一个元素会被多次收集(比如原列表里的b会被循环三次,每次都符合条件,导致结果里有三个b)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 12:28:12