如何递归合并列表列表元素的跳转对?我需要
'((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 。
答案 0 :(得分:4)
一种更简单的算法失败的情况:(f '((1 2) 3))
应该导致'((1 2 3))
,但是您的结果会导致错误。
我们将首先定义一些术语:
“元素”是常规元素,例如1
或'a
。
“普通列表”只是没有嵌套列表的“元素”列表。
例如,'(1 2 3)
是一个普通列表。 '((1 2) 3)
不是简单列表。
“普通列表”是:
empty
列表cons
的“元素”和下一个“普通列表” “跳跃对列表”是偶数长度的列表,其中奇数索引具有“普通列表”,而偶数索引具有元素。例如,'((1) 2 (a) 4)
是“跳跃对列表”。 “跳跃对列表”为:
empty
列表cons
个
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可能希望通过类型检查或添加代码来确保实现这一点,以确保不发生错误。