I’m writing a function that merges two lists. If one of the list’s item is a list, I need to extract it too.
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)
I tried to solve it by my code doesn’t work. What is the problem?
(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) '())))
The easiest way is to simply use the library function
flatten.flattentakes a list that can contain lists (who in turn can contain more lists, …) and flattens the result into a list of non-lists, which is what your combine function seems to be trying to do.(flatten '(1 2 (3 (4 5) 6)))returns'(1 2 3 4 5 6)If this library function is off limits, your code is actually pretty close to correct.
The first issue is on the
((list? lis) (combine (car lis) fine) (combine (cdr lis) fine) )line.fineis never changed, so the code evaluates(combine (car lis) fine)and then returns(combine (cdr lis) fine), where thefinein the second expression is the original value offine. This line is the same thing as((list? lis) (combine (cdr lis) fine) ), which is obviously not what we want. Instead, we have to use the first expression inside the second expression((list? lis) (combine (cdr lis) (combine (car lis) fine))).The second issue is that, in combine, when
lisis null, we need to returnfine, notlis.The next issue is that this code goes through the list, takes the first element of
lisand puts it on the front offine, and then passes the newly created list and uses it for the next iteration of the function, where it takes second value inlisand sticks it on the front of the newfine, in front of the first value oflis. The results in the order of the return value offinebeing reversed —(merge '(1 2 (3)) '(4 (5 6)))will return(6 5 4 3 2 1). We have two choices: we can call reverse on the return fromcombinein the body ofmergeor we can invert the line we changed above, making it((list? lis) (combine (car lis) (combine (cdr lis) fine))). This means that we would add the rest of the list tofinebefore adding the current element, which is what we want.Another issue is that we need to cons
lis1tolis2, not the other way around.The final issue is that the
condin the body ofmergeis unnecessary — we can remove it.As a side note, it is generally considered neater to not give close parentheses a new line and indent the body of a
defineorcondby just two spaces.With all of these changes, the final code is: