如何在Lisp的子列表中排序列表?

时间:2019-06-04 00:38:15

标签: lisp sublist

我有一个这样的列表:

(4 5 6 3 12 22 4 4 55 43 1 4 0) 

并想要这样的输出:

((4 5 6) (3) (12 22) (4) (4 55) (43) (1 4) (0)) 

我想您可以猜测顺序,顺序是升序,我对Lisp完全陌生,需要一些帮助

1 个答案:

答案 0 :(得分:2)

这是TXR Lisp中的一种可能的解决方案:

(defun ascending-partitions (list)
  (let ((indices (mappend (do if (>= @1 @2) (list @3))
                          list (cdr list) (range 1))))
    (split list indices)))

我们获得列表中元素的数字索引位置,这些位置不大于其前任元素;然后我们使用split函数在这些索引处将列表切成碎片。

通过使用mappend函数处理三个列表来完成索引的计算:原始list,与删除了第一个元素(cdr list)的相同列表并行,以及无限列表由(range 1)产生的以1开始的整数递增。

do宏为我们编写了一个匿名函数,其中嵌入表达式中的@1@2@3变量是该变量的三个参数,按此顺序。 mappend用从列表中并行获取的连续三重值调用此函数。因此,@1list中获取值,@2(cdr list)中获取连续值,@3从整数列表中获取连续值。每当@1至少与其后继@2一样大时,我们会将位置索引@3收集到一个元素列表中。 mappend将这些链接在一起。

与此相反,我们可以编写一个更直接的解决方案,该解决方案需要更多代码,但可以更好地利用机器资源:

(defun ascending-partitions (list)
  (let (partition output prev)
    (each ((item list))         ;; use (dolist (item list)  in Common Lisp
      (when (and prev (<= item prev))
        (when partition
          (push (nreverse partition) output)
          (set partition nil))) ;; use setf or setq in Common Lisp
      (push item partition)
      (set prev item))          ;; ditto
    (when partition
      (push (nreverse partition) output))
    (nreverse output)))