合并跳跃对

时间:2019-01-04 10:42:24

标签: list recursion racket

如何递归合并列表列表元素的跳转对?我需要

'((a b c) (e d f) (g h i))

来自

'((a b) c (e d) f (g h) i)

我的尝试

(define (f lst)      
  (if (or (null? lst)            
          (null? (cdr lst))) 
      '()                                                          
      (cons (append (car lst) (list (cadr lst))) 
            (list (append (caddr lst) (cdddr lst))))))

在我定义的情况下有效

(define listi '((a b) c (d e) f))

我从中获得

((a b c) (d e f))

简单地做

(f listi)

,但不适用于较长的列表。我知道我需要递归,但是我不知道在代码的最后一句话中再次在何处插入 f

3 个答案:

答案 0 :(得分:4)

一种更简单的算法失败的情况:(f '((1 2) 3))应该导致'((1 2 3)),但是您的结果会导致错误。

我们将首先定义一些术语:

  1. “元素”是常规元素,例如1'a

  2. “普通列表”只是没有嵌套列表的“元素”列表。 例如,'(1 2 3)是一个普通列表。 '((1 2) 3)不是简单列表。 “普通列表”是:

    • 一个empty列表
    • 一个cons的“元素”和下一个“普通列表”
  3. “跳跃对列表”是偶数长度的列表,其中奇数索引具有“普通列表”,而偶数索引具有元素。例如,'((1) 2 (a) 4)是“跳跃对列表”。 “跳跃对列表”为:

    • 一个empty列表
    • cons
      1. “普通列表”
      2. 一个cons的“元素”和下一个“跳跃对列表”

我们已经完成了术语。在编写函数之前,让我们从一些示例开始:

(f '())              equivalent to (f empty)

                     should output '()
                     equivalent to empty

(f '((1 2) 3))       equivalent to (f (cons (cons 1 (cons 2 empty)) 
                                            (cons 3 
                                                  empty)))

                     should output '((1 2 3))
                     equivalent to (cons (cons 1 (cons 2 (cons 3 empty)))
                                         empty)

(f '((1 2) 3 (4) a)) equivalent to (f (cons (cons 1 (cons 2 empty)) 
                                            (cons 3
                                                  (cons (cons 4 empty)
                                                        (cons 'a 
                                                              empty)))))

                     should output '((1 2 3) (4 a))
                     equivalent to (cons (cons 1 (cons 2 (cons 3 empty)))
                                         (cons (cons 4 (cons 'a empty))
                                               empty))

因此,f是一个使用“跳转对列表”并返回“普通列表”列表的函数。

现在,我们将编写函数f

(define (f lst)
  ???)

请注意,lst的类型是“跳跃对列表”,因此我们将直接对其进行案例分析:

(define (f lst)      
  (cond
    [(empty? lst) ???]               ;; the empty list case

    [else         ???                ;; the cons case has
                  (first lst)        ;; the "plain list",
                  (first (rest lst)) ;; the "element", and
                  (rest (rest lst))  ;; the next "list of jumping pairs"
                  ???]))             ;; that are available for us to use

从示例:

(f '())              equivalent to (f empty)

                     should output '()
                     equivalent to empty

我们知道空盒应该返回一个空列表,所以让我们相应地填充一个空洞:

(define (f lst)      
  (cond
    [(empty? lst) empty]             ;; the empty list case

    [else         ???                ;; the cons case has
                  (first lst)        ;; the "plain list",
                  (first (rest lst)) ;; the "element", and
                  (rest (rest lst))  ;; the next "list of jumping pairs"
                  ???]))             ;; that are available for us to use

从示例:

(f '((1 2) 3))       equivalent to    (f (cons (cons 1 (cons 2 empty)) 
                                               (cons 3 
                                                     empty)))

                     should output '((1 2 3))
                     equivalent to (cons (cons 1 (cons 2 (cons 3 empty)))
                                         empty)

我们知道我们绝对希望将“元素”放入“普通列表”的后面,以获得我们想要的结果“普通列表”:

(define (f lst)      
  (cond
    [(empty? lst) empty] ;; the empty list case

    [else ;; the cons case has:
          ???

          ;; the resulting "plain list" that we want
          (append (first lst) (cons (first (rest lst)) empty))

          ;; the next "list of jumping pairs"
          (rest (rest lst))   

          ;; that are available for us to use
          ???]))              

我们还需要处理下一个“跳跃对列表”,但是我们已经有一种应对方法:f

(define (f lst)      
  (cond
    [(empty? lst) empty] ;; the empty list case

    [else ;; the cons case has:
          ???

          ;; the resulting "plain list" that we want
          (append (first lst) (cons (first (rest lst)) empty))

          ;; the list of "plain list"
          (f (rest (rest lst)))

          ;; that are available for us to use
          ???]))

然后我们可以返回答案:

(define (f lst)      
  (cond
    [(empty? lst) empty] ;; the empty list case

    [else ;; the cons case returns
          ;; the resulting list of "plain list" that we want
          (cons (append (first lst) (cons (first (rest lst)) empty))
                (f (rest (rest lst))))]))

答案 1 :(得分:1)

Pattern matching(在下面使用match)对于此类问题非常有用-

(define (f xs)
  (match xs
    ;; '((a b) c . rest)
    [(list (list a b) c rest ...)
     (cons (list a b c)
           (f rest))]
    ;; otherwise
    [_
     empty]))

define/match为这种通用过程样式提供了一些语法糖,使事情变得更好-

(define/match (f xs)
  [((list (list a b) c rest ...))
   (cons (list a b c)
         (f rest))]
  [(_)
   empty])

还有一个尾递归修订-

(define (f xs)
  (define/match (loop acc xs)
    [(acc (list (list a b) c rest ...))
     (loop (cons (list a b c) acc)
           rest)]
    [(acc _)
     acc])
  (reverse (loop empty xs)))

每个程序的输出都相同-

(f '((a b) c (e d) f (g h) i))
;; '((a b c) (e d f) (g h i))

(f '((a b) c))
;; '((a b c))

(f '((a b) c x y z))
;; '((a b c))

(f '(x y z))
;; '()

(f '())
;; '()

作为额外的奖励,此答案不使用昂贵的append操作

答案 2 :(得分:0)

您的代码中没有递归的情况,因此它将仅对4个元素的列表静态起作用。您需要支持以下内容:

(f '()) ; ==> ()
(f '((a b c) d (e f g) h)) ; ==> (cons (append '(a b c) (list 'd)) (f '((e f g) h)))

现在,这需要完全偶数个元素,并且每个奇数元素都是一个正确的列表。没什么问题,但是onw可能希望通过类型检查或添加代码来确保实现这一点,以确保不发生错误。