代码之家  ›  专栏  ›  技术社区  ›  selubamih

如何创建n维列表?

  •  0
  • selubamih  · 技术社区  · 6 年前

    作为一个初学者,我在唇部挣扎,在我的程序中我有一个列表,比如:
    (((NIL (B) (C) (B)) (A)) (E) (G))

    但我要构建的是n维列表(在本例中是3维):

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

    我试过把名单压平,但似乎不对。我会感谢你的帮助。

    2 回复  |  直到 6 年前
        1
  •  4
  •   tfb    6 年前

    由于您没有真正给出程序要做什么的规范,这里有一些东西可以将您所拥有的结构转变为您想要的结构,前提是其他东西正在给您这个结构。

    你的结构是一个缺点,如果没有更多的结构,它的car或者是空的,或者是一个结构。单个元素列表的结构列表的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树。你可以用这个来检查一下往返是否正常。

    (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))
    

    还有另一组用于处理斑点树的功能,它们(事实证明)只是用它们的汽车和换用的CDR构建的列表:

    ;;; 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)))
    

    这意味着,如果表示改变了这两个稍微多毛的函数,则不会。

        2
  •  0
  •   Kaz    6 年前

    这对我很有用:

    (defun peculiar-transform (input-list)
      (destructuring-bind (((ignore (xb) (xc) (xb)) (xa)) (xe) (xg)) input-list
        `((,xb ,xc ,xb) (,xa) (,xe ,xg))))
    

    测试:

    [1]> (peculiar-transform '(((NIL (B) (C) (B)) (A)) (E) (G)))
    ((B C B) (A) (E G))
    [2]> (peculiar-transform '(((NIL (2) (3) (2)) (1)) (5) (7)))
    ((2 3 2) (1) (5 7))
    

    我已将变量重命名为 XA , XB ,…只是为了减少使用 A , B ,…在输入测试用例中发生。

    这是我们的优势 destructuring-bind 要直接使用输入模式(只需重命名变量)作为如何提取元素的规范,然后使用后引号语法生成具有所需输出形状的模板,将提取的部分插入正确的位置。