You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何按cdr元素对cons列表进行排序?

按cons元素的cdr排序(或符号中的数字部分排序)

嘿,作为Lisp新手,这个问题其实很适合用标准库的sort函数来解决,不过先得澄清一个语法细节——你示例里的aaa.4写法容易混淆:在Common Lisp里,(aaa . 4)是真正的cons对(car是符号aaa,cdr是数字4),而aaa.4是一个单独的符号(名字包含点和数字)。我会两种情况都给你讲清楚:

情况1:元素是真正的cons对

如果你的输入是由(符号 . 数字)这样的cons对组成的列表,比如((aaa . 4) (bbb . 2) (ccc . 6) (ddd . 9) (eee . 3)),直接用sort加一个自定义的比较谓词就行:

;; 注意:sort是破坏性函数,会修改原列表,用copy-list保留原列表
(sort (copy-list '((aaa . 4) (bbb . 2) (ccc . 6) (ddd . 9) (eee . 3)))
      (lambda (x y)
        (< (cdr x) (cdr y))))

运行后会得到你想要的结果:((bbb . 2) (eee . 3) (aaa . 4) (ccc . 6) (ddd . 9))

代码解释:

  • copy-list:复制原列表,避免sort修改你原来的输入列表(Common Lisp的sort会直接修改传入的序列,这是它的特性)
  • 匿名函数(lambda (x y) (< (cdr x) (cdr y))):作为排序的判断规则,每次取两个cons对x和y,比较它们的cdr部分,只要x的cdr比y小,就把x排在y前面,实现升序排序。

情况2:元素是带数字的符号

如果你的输入确实是(aaa.4 bbb.2 ...)这种符号组成的列表,那需要先从符号名里提取出后面的数字,再排序。我们可以写一个小函数来提取数字:

;; 从符号中提取点后面的数字
(defun extract-number-from-symbol (sym)
  (let* ((sym-str (string sym))
         (dot-pos (position #\. sym-str)))
    (parse-integer (subseq sym-str (1+ dot-pos)))))

;; 排序代码
(sort (copy-list '(aaa.4 bbb.2 ccc.6 ddd.9 eee.3))
      (lambda (x y)
        (< (extract-number-from-symbol x)
           (extract-number-from-symbol y))))

运行后会输出:(bbb.2 eee.3 aaa.4 ccc.6 ddd.9),完全符合你的示例要求。

代码解释:

  • extract-number-from-symbol:把符号转成字符串,找到点的位置,截取点后面的子字符串,再转成整数。比如aaa.4会被转换成字符串"AAA.4",提取出"4"并转为整数4。
  • 排序时,用这个函数提取两个符号的数字部分,比较大小后完成排序。

新手小提示

  • 一定要注意cons对的语法:(car . cdr)里的点前后必须有空格,否则会被当成一个符号,这是新手很容易踩的坑。
  • 如果你不需要保留原列表,可以去掉copy-list,直接给sort传原列表就行,但一般建议保留原数据,避免意外修改。

内容的提问来源于stack exchange,提问作者Леонид Захаров

火山引擎 最新活动