2012-02-23 107 views
3

我在写一个合并两个列表的函数。如果列表中的一个项目是列表,我也需要提取它。合并和提取列表

list1:'(1 (2 3 4) 5 6)) 

list2: '(7 (8 9) 10 (11)) 

output: (1 2 3 4 5 6 7 8 9 10 11) 

我试图通过我的代码解决它不起作用。问题是什么?

(define (merge lis1 lis2) 
    (define (combine lis fine) 
     (cond 
      ((null? lis) lis) 
      ((list? lis) (combine (car lis) fine) (combine (cdr lis) fine)) 
      (else (cons lis fine)))) 

     (cond 
      (combine (cons lis2 lis1) '()))) 

回答

10

最简单的方法是简单地使用库函数flatten

(define (merge lis1 lis2) 
    (flatten (cons lis1 lis2))) 

flatten需要,可以包含列表(谁又可以包含多个列表,...)的列表,并将结果合并为未列出的清单,这是你的组合功能似乎什么是试图去做。

(flatten '(1 2 (3 (4 5) 6)))回报'(1 2 3 4 5 6)

如果这个库的功能是关闭的限制,你的代码实际上是相当接近正确。

第一个问题是在((list? lis) (combine (car lis) fine) (combine (cdr lis) fine) )行。 fine永不改变,因此代码评估(combine (car lis) fine),然后返回(combine (cdr lis) fine),其中第二个表达式中的fine是原始值fine。这条线与((list? lis) (combine (cdr lis) fine) )相同,显然不是我们想要的。相反,我们必须使用第二个表达式((list? lis) (combine (cdr lis) (combine (car lis) fine)))中的第一个表达式。

第二个问题是,在组合中,当lis为空时,我们需要返回fine而不是lis

下一个问题是,这段代码遍历列表,将lis的第一个元素放在fine的前面,然后传递新创建的列表并将其用于下一次函数迭代,其中它在lis中取第二个值,并将其粘贴在新的fine的前面,在lis的第一个值前面。返回值为fine的结果顺序颠倒 - (merge '(1 2 (3)) '(4 (5 6)))将返回(6 5 4 3 2 1)。我们有两种选择:我们可以在merge正文中从combine返回,或者我们可以反转我们上面更改的行,使其成为((list? lis) (combine (car lis) (combine (cdr lis) fine)))。这意味着在添加当前元素之前,我们会将列表的其余部分添加到fine,这正是我们想要的。

另一个问题是我们需要将lis1改为lis2,而不是相反。

最后一个问题是merge正文中的cond是不必要的 - 我们可以将其删除。

作为一个方面说明,通常认为整齐的方法是不要给圆括号一个新的行,并将definecond的主体缩进两个空格。

所有这些变化,最终的代码是:

(define (merge lis1 lis2) 
    (define (combine lis fine) 
    (cond 
     ((null? lis) fine) 
     ((list? lis) (combine (car lis) 
          (combine (cdr lis) fine))) 
     (else (cons lis fine)))) 

    (combine (cons lis1 lis2) '()))