Dr.Racket中item-counts列表元素计数函数实现问题
Racket
item-counts 函数实现方案 现有代码存在3个直接导致运行错误、结果结构异常的问题:
- 基础分支返回值类型不统一:处理单元素列表时直接返回裸元素(字符串、布尔值等),其余递归分支返回列表,后续拼接时必然出现层级混乱
- 缺失核心计数逻辑:仅完成了元素相等判断,未实现「匹配到重复元素时计数+1、未匹配时新增计数条目」的逻辑
cons语法使用错误:Racket 中cons仅接收2个参数,测试用例中传入3~4个参数的写法本身不符合语法,计数结果的标准结构为关联列表:每个元素是(值 . 计数)格式的 cons 对,所有 cons 对组成最终结果列表。
可直接运行的正确代码
首先修正测试用例为合法语法:
(check-expect (item-counts (cons "hello" (cons "hey" (cons "hello" '()))) equal?) (list (cons "hello" 2) (cons "hey" 1))) (check-expect (item-counts (cons #true (cons #false (cons #true '()))) equal?) (list (cons #true 2) (cons #false 1)))
函数实现采用原生递归,每次处理当前元素前先递归得到剩余列表的统计结果,再判断当前元素是否已被统计:匹配到则更新计数替换旧条目,未匹配则新增计数为1的新条目。
(define (item-counts lop ef) (cond ; 空输入对应空统计结果 [(empty? lop) '()] [else (define rest-counts (item-counts (rest lop) ef)) (define current (first lop)) ; 在已有统计结果中查找当前元素 (define exist-pair (assf (lambda (x) (ef current x)) rest-counts)) (if exist-pair ; 存在重复:移除旧条目,追加计数+1的新条目 (cons (cons current (add1 (cdr exist-pair))) (filter (lambda (p) (not (ef current (car p)))) rest-counts)) ; 不存在重复:新增计数为1的条目 (cons (cons current 1) rest-counts))]))
之前调用append出现嵌套列表的原因
append 要求所有传入参数必须是列表类型,之前的代码因为基础分支返回非列表类型的裸元素,传入append时会被当成单个列表元素处理,而非作为列表拼接,最终生成多层嵌套的错误结构。
如果需要返回键值交替的扁平列表(如(list "hello" 2 "hey" 1)),只需要在上述函数的最终返回结果外调用flatten拉平结构即可。但关联列表是Racket生态中处理键值计数场景的标准结构,后续做查询、更新、遍历操作都更便捷。
内容的提问来源于stack exchange,提问作者daniel
相关产品推荐
相关产品推荐

