在LISP中,首先从列表中排序原子,然后再从列表中排序子列表

在LISP中,首先从列表中排序原子,然后再从列表中排序子列表,lisp,common-lisp,difference-lists,Lisp,Common Lisp,Difference Lists,我有一个LISP作业,我需要从列表中排序原子和子列表。我相信这应该是一个简单的任务,但由于我不是一个程序员,那么这真的需要相当长的一段时间来理解 我有一份数字清单: (5 -1 (2 6 1) (8 7 -3) (0 (9 4)) -6) 如果我正确理解了我的任务,那么我应该得到如下结果: (5 -1 -6 (2 6 1) (8 7 -3) (0 (9 4))) 到目前为止,我所知道的只是如何计算原子和/或子列表,但我不需要这些 (DEFUN ATOMNUMBER (L) (COND ((N

我有一个LISP作业,我需要从列表中排序原子和子列表。我相信这应该是一个简单的任务,但由于我不是一个程序员,那么这真的需要相当长的一段时间来理解

我有一份数字清单:

(5 -1 (2 6 1) (8 7 -3) (0 (9 4)) -6)
如果我正确理解了我的任务,那么我应该得到如下结果:

(5 -1 -6 (2 6 1) (8 7 -3) (0 (9 4)))
到目前为止,我所知道的只是如何计算原子和/或子列表,但我不需要这些

(DEFUN ATOMNUMBER (L) (COND ((NULL L) 0)
  ((ATOM (CAR L)) (+ 1 (ATOMNUMBER (CDR L))))
  (T (ATOMNUMBER (CDR L))) ))
而且,即使只有子列表、原子或空列表,该函数也应该正常工作

也许有人能给我举一些例子


提前谢谢

在通用Lisp中有几种可能的方法:

  • 使用REMOVE-IF删除不需要的项目。(或者使用REMOVE-IF-NOT保留想要的项目。)您将需要两个列表。附加它们

  • 使用DOLIST并迭代列表,将项目收集到两个列表中并附加它们

  • 编写一个需要保留两个结果列表的递归过程

  • 还可以将SORT与特殊的SORT谓词一起使用

例如:

> (sort '(1 (2 6 1) 4 (8 7 -3) 4 1 (0 (9 4)) -6 10 1)
        (lambda (a b)
           (atom a)))

(1 10 -6 1 4 4 1 (2 6 1) (8 7 -3) (0 (9 4)))
作为稳定版本:

(stable-sort '(1 (2 6 1) 4 (8 7 -3) 4 1 (0 (9 4)) -6 10 1)
             (lambda (a b)
               (and (atom a)
                    (not (atom b)))))

(1 4 4 1 -6 10 1 (2 6 1) (8 7 -3) (0 (9 4)))

我更习惯于Scheme,但这里有一个在Lisp中工作的解决方案:

(defun f (lst)
  (labels 
      ((loop (lst atoms lists)
         (cond
          ((null lst) 
           (append (reverse atoms) (reverse lists)))
          ((atom (car lst))
           (loop (cdr lst) (cons (car lst) atoms) lists))
          (T
           (loop (cdr lst) atoms (cons (car lst) lists))))))
    (loop lst '() '())))

(f '(5 -1 (2 6 1) (8 7 -3) (0 (9 4)) -6))
基本上,您在列表上进行迭代,每个元素要么附加到原子列表,要么附加到列表。最后,你将两者结合起来以获得结果

编辑

如果删除版本要短得多,当然:

(let ((l '(5 -1 (2 6 1) (8 7 -3) (0 (9 4)) -6)))
   (append
    (remove-if-not #'atom l)
    (remove-if     #'atom l)))

下面是一段迭代代码,以自顶向下的方式构造其输出(注释采用Haskell语法):


以自顶向下的方式构建的两个中间列表被维护为开放式列表(即带有显式结束指针),基本上遵循差异列表范式

以防万一你想多锻炼,你会发现这里提供的例子还不够:p

(defun sort-atoms-first-recursive (x &optional y)
  (cond
    ((null x) y)
    ((consp (car x))
     (sort-atoms-first-recursive (cdr x) (cons (car x) y)))
    (t (cons (car x) (sort-atoms-first-recursive (cdr x) y)))))

(defun sort-atoms-first-loop (x)
  (do ((a x (cdr a))
       (b) (c) (d) (e))
      (nil)
    (if (consp (car a))
      (if b (setf (cdr b) a b (cdr b)) (setf b a d a))
      (if c (setf (cdr c) a c (cdr c)) (setf c a e a)))
    (when (null (cdr a))
      (cond
        ((null d) (return e))
        ((null c) (return d))
        (t (setf (cdr b) nil (cdr c) d) (return e))))))


(sort-atoms-first-recursive '(5 -1 (2 6 1) (8 7 -3) (0 (9 4)) -6))

(sort-atoms-first-loop '(5 -1 (2 6 1) (8 7 -3) (0 (9 4)) -6))

第二个是破坏性的(但不会产生任何新的消耗)。

您可以通过以下递归方式:

(defun f (lst) 
    (cond 
        ((null lst) nil)
        ((atom (car lst)) 
        (append (list (car lst)) (f (cdr lst)))) 
        (T
            (append (f (cdr lst)) (list (f (car lst))))
        )
    )
)
(step (f '(5 -1 (2 6 1) (8 7 -3) (0 (9 4)) -6)))
输出:

step 1 --> (F '(5 -1 (2 6 1) (8 7 -3) ...))                                                                   
step 1 ==> value: (5 -1 -6 (0 (9 4)) (8 7 -3) (2 6 1))

谢谢,这将有助于我的下一个任务(类似于第一个任务);但使用此谓词,即使是
稳定排序
也会返回与
排序
相同的结果。请给出一个示例,我应该在第一个代码中编辑什么,以便它可以对矩阵中的原子进行排序?例如,我有((45)2)(3(2)5)(4(0)26)),它应该像这样对原子排序:((2(45))(35(2))(42(0)))试试(mapcar#f((45)2)(3(2)5)(4(0)26))。不客气。只要确保你真正理解它为什么有效。如果没有,请毫不犹豫地再次询问。
step 1 --> (F '(5 -1 (2 6 1) (8 7 -3) ...))                                                                   
step 1 ==> value: (5 -1 -6 (0 (9 4)) (8 7 -3) (2 6 1))