首页 > 解决方案 > 如何创建 n 维列表?

问题描述

作为初学者,我在嘴唇上苦苦挣扎,在我的程序中,我有一个类似的列表:
(((NIL (B) (C) (B)) (A)) (E) (G))

但我要构建的是 n 维列表(在这种情况下为 3-dim):

((B C B)(A)(E G))

我尝试过扁平化列表,但它似乎不正确。我将不胜感激。

标签: listlisp

解决方案


由于您还没有真正给出程序要做什么的规范,因此假设其他东西正在给您这种结构,这里有一些东西可以将您拥有的结构变成您想要的结构。

你的结构是一个缺点,如果没有更多的结构,它的汽车要么是空的,要么是结构。单元素列表的结构列表的 cdr 和我们想要的那些元素。

我称这个结构为 BLOB-TREE,每个 CDR 都是一个 BLOB。

(defun blob-to-list (blob)
  ;; a blob is a list of single-element lists, and we want the elements
  (mapcar (lambda (e)
            (assert (and (listp e) (null (rest e))))
            (first e))
          blob))

(defun blob-tree-to-list (blobs)
  ;; BLOB-TREE is some horrible tree: what we need to do is split it into
  ;; its car & cdr, and then convert the cdr to a list with
  ;; blob-to-list, then recurse on the car, until we get a null car.
  (labels ((extract-blobs (remains accum)
             (etypecase remains
               (null accum)
               (cons
                (extract-blobs (car remains) (cons (blob-to-list (cdr remains))
                                                   accum))))))
    (extract-blobs blobs '())))

现在

> (blob-tree-to-list '(((NIL (B) (C) (B)) (A)) (E) (G)))
((b c b) (a) (e g))

我相当怀疑这实际上是你想要做的。


作为检查,我编写了一个函数,它以您想要的形式获取一个列表并将其转换为一个 blob-tree。您可以使用它来检查是否正确往返。

(defun list-to-blob-tree (l)
  (labels ((list-to-blob (es)
             (mapcar #'list es))
           (build-blob-tree (tail accum)
             (if (null tail)
                 accum
               (build-blob-tree (rest tail)
                                (cons accum (list-to-blob (first tail)))))))
    (build-blob-tree l '())))

如果你真的想处理这样的事情(在现实生活中,你有时不得不这样做),一个好的方法是编写一堆访问器函数,让你抽象出你已经获得的不可靠的数据结构。

在这种情况下,我们可以编写函数来处理 blob:

;;; Blobs are lists are lists where each element is wrapped in a
;;; single-element list

(defun blob->element-list (blob)
  ;; a blob is a list of single-element lists, and we want the elements
  (mapcar (lambda (e)
            (assert (and (listp e) (null (rest e))))
            (first e))
          blob))

(defun element-list->blob (list)
  ;; turn a list into a blob
  (mapcar #'list list))

还有一组处理 blob 树的函数,(事实证明)只是用他们的汽车和 cdrs 交换构建的列表:

;;; Blob trees are lists, built backwards
;;;

(deftype blob-tree ()
  '(or cons null))

(defconstant null-blob-tree nil)

(defun blob-tree-car (blob-tree)
  (cdr blob-tree))

(defun blob-tree-cdr (blob-tree)
  (car blob-tree))

(defun blob-tree-cons (car cdr)
  (cons cdr car))

(defun blob-tree-null-p (blob-tree)
  (null blob-tree))

在这两种情况下,我只编写了我需要的函数:例如,有读者但没有作者。

现在我们可以根据这些抽象来编写我们需要的函数:

(defun blob-tree->element-list (blob-tree)
  (labels ((extract-blobs (tree accum)
             (assert (typep tree 'blob-tree))
             (if (blob-tree-null-p tree)
                 accum
               (extract-blobs (blob-tree-cdr tree)
                              (cons (blob->element-list (blob-tree-car tree))
                                    accum)))))
    (extract-blobs blob-tree '())))

(defun element-list->blob-tree (el)
  (labels ((build-blob-tree (elt accum)
             (if (null elt)
                 accum
               (build-blob-tree (rest elt)
                                (blob-tree-cons
                                 (element-list->blob (first elt))
                                 accum)))))
    (build-blob-tree el null-blob-tree)))

这意味着如果表示发生变化,这两个轻度毛茸茸的函数不会。


推荐阅读