LISP新手求助:如何获取嵌套列表的平均长度?
如何用LISP获取嵌套列表的平均长度?
别担心,刚接触LISP的时候碰到这种嵌套列表的处理问题太正常了,我来一步步帮你拆解这个函数框架,搞清楚每个部分的逻辑,再帮你修正自己写的代码。
先明确需求
我们要实现的是:遍历外层列表,找出所有的子列表(跳过非列表元素),计算这些子列表的长度总和,再除以子列表的数量,最终得到平均长度(用浮点数展示结果更直观)。
拆解给定的函数框架
先把框架里的空位逐个填上,再逐一解释每个部分的逻辑:
(defun nested-lists-average-length (ls &aux (i 0) (n 0)) ; dolist遍历ls里的每个元素a,循环结束后返回浮点数形式的平均值 (dolist (a ls (float (/ i n))) ; 判断当前元素a是不是列表(只处理子列表类型的元素) (if (listp a) (progn ; 把当前子列表的长度加到总和i里 (incf i (length a)) ; 子列表的计数n加1 (incf n 1)))))
逐个解析空位的填充原因:
dolist的返回值部分:(float (/ i n))——i是所有子列表长度的总和,n是子列表的总数量,用float把整数除法转成浮点数,避免只得到取整后的整数结果(比如总和5、数量2,直接/会得到2,float后会得到更准确的2.5)。(if (listp a))——listp是LISP里判断一个元素是否为列表的标准函数,我们只需要处理列表类型的子元素,非列表元素直接跳过。(incf i (length a))——incf是增量快捷函数,效果等同于(setq i (+ i (length a))),用来把当前子列表的长度累加到总和i中。(incf n 1)——每找到一个合格的子列表,就把计数n加1,统计子列表的总数量。
修正你自己写的函数
你写的代码方向是对的,但有两个关键问题需要调整:
- 错误地用
plusp判断元素:plusp是用来判断正数的,不是判断列表的,应该换成listp。 - 未完成的
(min...其实应该是获取子列表的长度(length x)。
修正后的完整版本:
(defun average-sublist-length (list &aux (sum 0) (n 0)) ; 遍历每个元素x,当n大于0时返回平均值(避免外层无列表时出现除以0的错误) (dolist (x list (when (plusp n) (float (/ sum n)))) ; 只处理列表类型的元素 (when (listp x) ; 累加子列表长度到sum (incf sum (length x)) ; 子列表计数加1 (incf n 1))))
这里额外加了(when (plusp n))的判断,是为了避免外层列表里没有子列表时出现除以0的错误,此时函数会返回nil,逻辑更安全。
测试示例
用这个函数测试几个场景:
(nested-lists-average-length '((1 2) (3) "abc" (4 5 6))) ; 有效子列表是(1 2)(长度2)、(3)(长度1)、(4 5 6)(长度3),总和6,数量3,平均值2.0 ; 返回结果:2.0 (average-sublist-length '((a b c) 123 (d))) ; 有效子列表长度总和3+1=4,数量2,平均值2.0 ; 返回结果:2.0
内容的提问来源于stack exchange,提问作者Joe B Rock
相关产品推荐
相关产品推荐

