2012-02-23 3 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). У нас есть два варианта: мы можем называть обратное по возврату от combine в теле merge, или мы можем инвертировать линию, которую мы изменили выше, делая ее ((list? lis) (combine (car lis) (combine (cdr lis) fine))). Это означает, что мы добавим остальную часть списка в fine перед добавлением текущего элемента, который мы хотим.

Другая проблема заключается в том, что нам нужны минусы lis1 до lis2, а не наоборот.

Последний выпуск: cond в корпусе merge не нужно - мы можем его удалить.

В качестве примечания стороны, как правило, считается более аккуратным, чтобы не давать близких круглых скобок новую строку и отступать от тела define или cond всего двумя пробелами.

С учетом всех этих изменений, окончательный код:

(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) '()))