映射到嵌套序列树

时间:2016-12-17 17:28:30

标签: tree mapping common-lisp sequences

我编写了一个函数,旨在映射到嵌套的正确列表的任意树,有点类似于常见的lisp函数map-into

(defun map-into-tree (fn tree)
  "Destructive mapping into a proper tree."
  (cond ((null tree) nil)
        ((atom (car tree)) 
         (setf (car tree) (funcall fn (car tree))) 
         (map-into-tree fn (cdr tree)))
        (t (map-into-tree fn (car tree)) 
           (map-into-tree fn (cdr tree)))))

(defparameter *tree* '(1 (2) ((3)) (4 5) (6 ((7)))))
*TREE*

(map-into-tree #'1+ *tree*)
NIL

*tree*
(2 (3) ((4)) (5 6) (7 ((8))))

但是,我不确定如何对任意嵌套序列进行概括(如序列的map-into)。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:0)

这是一个可能的解决方案:

(defun map-into-nested-list (fn nested-list)
  "Destructive mapping into a nested-list."
  (cond ((null nested-list) nil)
        ((atom (car nested-list)) 
         (when (car nested-list) (setf (car nested-list) (funcall fn (car nested-list))))
         (map-into-nested-list fn (cdr nested-list)))
        ((atom (cdr nested-list)) 
         (when (cdr nested-list) (setf (cdr nested-list) (funcall fn (cdr nested-list))))
         (map-into-nested-list fn (car nested-list)))
        (t (map-into-nested-list fn (car nested-list)) 
           (map-into-nested-list fn (cdr nested-list)))))

(defvar *a* (copy-tree '((9 10) (8 9 10 11 (12 13) () (11) () 13))))
;; => *A*
(map-into-nested-list #'1+ *a*)
;; => NIL
*a*
;; => ((10 11) (9 10 11 12 (13 14) NIL (12) NIL 14))

该函数类似于map-into-tree:主要区别在于cdr是原子的情况下条件中存在一个新的对称分支,并且测试“原子”情况仅在原子与fn不同时才应用函数NIL

答案 1 :(得分:0)

你可以致电map-into; - )

(defun map-into-tree (function tree)
  (labels
      ((recurse (tree)
         (typecase tree
           (sequence (map-into tree #'recurse tree))
           (t (funcall function tree)))))
    (recurse tree)))

......或等效地:

(defun map-into-tree (function tree)
  (typecase tree
    (sequence (map-into tree (lambda (u) (map-into-tree function u)) tree))
    (t (funcall function tree))))

测试:

(map-into-tree #'1+ (copy-tree '((9 10) (8 9 10 11 (12 13) () (11) () 13))))
=> ((10 11) (9 10 11 12 (13 14) NIL (12) NIL 14))

我不确定包含字符串的树会发生什么:我们真的想迭代每个字符吗?事实上,这就是上面所做的。

  

我还注意到map-into与包含cons单元格的序列一起工作,但相应的map-to-tree不会,即使它使用map-into。

(1 (2 . 3))是一个包含两个元素的正确列表,即1(2 . 3)。由于map-into没有递归到元素中,所以它只是在这两个元素上调用函数。在您的评论中,这是print,可以毫无问题地打印不正确的列表。

第二个元素是一个序列:当你调用map-into-tree时,函数以这个序列递归调用map-into,这恰好是一个不正确的列表。 map-into期望正确的序列,因此使用不正确的列表会失败。

请注意,在你的问题中,你说:

  

一个旨在映射到嵌套正确列表的任意树

的函数

包含不正确列表的树不是有效输入。

最后,我注意到你在文字数据上调用了破坏性函数,如下所示:

(map-into #'print '(1 2))

引用列表是常量,在运行时修改它是未定义的行为。这就是我在我的例子中首次使用copy-tree的原因。

  

这样可以处理所有特殊情况[...]

由于已经存在一个类型规划,因此处理cons的特殊情况就足够了;无论cdr插槽中保存的值类型如何,它都能正常工作:

(defun map-into-tree (function tree)
  (labels
      ((walk (tree)
         (typecase tree
           (cons
            (prog1 tree
              (setf (car tree) (walk (car tree)))
              (setf (cdr tree) (walk (cdr tree)))))
           (sequence (map-into tree #'walk tree))
           (t (funcall function tree)))))
    (walk tree)))