【问题标题】:Remove self-references from a circular list从循环列表中删除自引用
【发布时间】:2015-03-10 20:40:40
【问题描述】:

我在 Common Lisp 中有一个复杂的循环数据结构:

(defvar xs '#1=(1 #2=(#1# 2 #3=(#2# 3 #4=(#3# 4 #1#)))))

如何将其转换为非循环列表,以便每次出现的自引用都替换为nil?所以我有(1 (nil 2 (nil 3 (nil 4 nil))))而不是(1 (#0 2 (#1 3 (#2 4 #0))))

【问题讨论】:

    标签: common-lisp circular-reference circular-list


    【解决方案1】:

    最简单的方法是使用哈希表了解您遇到的所有cons。即使循环发生在cdr 中,此版本也能正常工作:

    (defun remove-ref (list &optional (value nil))
      (let ((h (make-hash-table :test #'eq)))
        (labels ((rraux (list)
                   (cond ((gethash list h) value)
                         ((not (consp list)) list)
                         (t (setf (gethash list h) t)
                            (cons (rraux (car list)) 
                                  (rraux (cdr list)))))))
          (rraux list))))
    
    
    (remove-ref '#1=(1 2 #2=(3 4 5 . #1#) 6 7 . #1#) 'test) 
    ; ==> (1 2 (3 4 5 . test) 6 7 . test)
    (remove-ref '#1=(1 2 #2=(3 4 5 . #1#) 6 7 . #1#)) 
    ; ==> (1 2 (3 4 5) 6 7)
    

    【讨论】:

      【解决方案2】:

      只需递归迭代列表及其子列表,记住您之前遇到过哪些:

      (defun remove-circles (list)
        (let ((seen (make-hash-table :test 'eq)))
          (labels ((rec (datum)
                     (cond ((not (listp datum))
                            datum)
                           ((gethash datum seen)
                            nil)
                           (t
                            (setf (gethash datum seen) t)
                            (mapcar #'rec datum)))))
            (rec list))))
      
      * (defvar xs '#1=(1 #2=(#1# 2 #3=(#2# 3 #4=(#3# 4 #1#)))))
      XS
      * xs
      #1=(1 #2=(#1# 2 #3=(#2# 3 (#3# 4 #1#))))
      * (remove-circles xs)
      (1 (NIL 2 (NIL 3 (NIL 4 NIL))))
      

      这会创建一个新列表 - 原始结构不会被修改。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-27
        • 1970-01-01
        • 2021-11-28
        • 2018-02-16
        • 1970-01-01
        • 1970-01-01
        • 2015-11-10
        • 2014-08-26
        相关资源
        最近更新 更多