【问题标题】:Turning list of atoms into a single list using recursion使用递归将原子列表转换为单个列表
【发布时间】:2013-08-07 13:44:47
【问题描述】:

我正在寻找将原子列表递归地转换为单个列表的答案。

例如,(slist '(a (b c) (d e (f) g) h)) 变为 (slist (a b c d e f g h))

任何答案都会有所帮助。

【问题讨论】:

    标签: list recursion lisp scheme


    【解决方案1】:

    您正在尝试做的事情称为扁平化列表。这里有很多选项:

    ; required predicate
    
    (define (atom? x)
      (and (not (null? x))
           (not (pair? x))))
    
    ; naïve version using append
    
    (define (flatten1 lst)
      (cond ((null? lst)
             '())
            ((not (pair? lst))
             (list lst))
            (else
             (append (flatten1 (car lst))
                     (flatten1 (cdr lst))))))
    
    ; naïve version using append, map, apply
    
    (define (flatten2 lst)
      (if (atom? lst)
          (list lst)
          (apply append (map flatten2 lst))))
    
    ; efficient version using fold-left
    
    (define (flatten3 lst)
      (define (loop lst acc)
        (if (atom? lst)
            (cons lst acc)
            (foldl loop acc lst)))
      (reverse (loop lst '())))
    
    ; very efficient version with no higher-order procedures
    
    (define (flatten4 lst)
      (let loop ((lst lst)
                 (acc '()))
        (cond ((null? lst)
               acc)
              ((not (pair? lst))
               (cons lst acc))
              (else
               (loop (car lst) (loop (cdr lst) acc))))))
    

    以上任何一项都将按预期工作。例如,使用flatten4:

    (flatten4 '(a (b c) (d e (f) g) h))
    => '(a b c d e f g h)
    

    根据您使用的解释器,它很可能已经包含一个实现。例如,在球拍中:

    (flatten '(a (b c) (d e (f) g) h))
    => '(a b c d e f g h)
    

    【讨论】:

    • 这就是所谓的扁平化。多谢。这是很多的学习。 :D
    【解决方案2】:

    在 Lisp 中,与 Scheme 不同,您必须接受这样一个事实,即原子 nil 表示列表结构中的一个空列表。所以,严格来说,当你展平一个列表时,你并没有从树结构中获得所有的原子;只有那些不代表空列表和列表终止符的。

    您还必须做出设计决定:您的代码是否处理不正确的列表和循环列表?也就是说,这些case应该怎么办:

    (flatten '(a . b))  ;; (a b), accurate diagnostic or failure?
    
    (flatten '#1=(a . #1#))  ;; (a), accurate diagnostic or failure?
    

    您是否处理这种情况并收集存在于树结构中的实际非列表原子,而不管循环或不正确的终止如何?或者您是否准确地检测到情况并报告有意义的诊断?或者只是忽略这种可能性,让代码在较低级别的函数中爆炸,或者执行失控递归?

    如果您不关心处理不正确的列表和循环结构,则将列表展平是这样递归定义的。

    1. 通过返回包含该原子的列表来展平非列表。
    2. 通过展平其所有元素并将它们连接起来来展平列表。

    在 Lisp 中,编写代码通常比英文规范或伪代码更容易、更清晰:

    (defun flatten (obj)
    "Simple flatten: no handling of improper lists or cycles"
       (if (listp obj)
         (mapcan #'flatten obj)
         (list obj)))
    

    请注意,尽管mapcan 具有破坏性,但这在这里并不存在问题,因为它只会连接在我们的函数调用中构造的列表结构,而不是任何传入的列表结构。换句话说,我们的输出与输入不共享结构。

    【讨论】:

    【解决方案3】:

    你已经检查了一个正确的答案,但这里有一个简单的实现,它清楚地表明了递归:

    (define (slist list)
      (if (null? list)
          '()
          (let ((next (car list))
                (rest (cdr list)))
            (if (list? next) 
                (append (slist next) (slist rest))
                (cons next (slist rest))))))
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-21
    • 2020-05-24
    • 1970-01-01
    • 1970-01-01
    • 2013-12-22
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    相关资源
    最近更新 更多