Merging Two Lists in Racket R5RS - list

I'm supposed to create a function called ( merge-list lst1 lst2) that alternately picks elements from one of the two input lists and creates a new list. For example the output of
(merge-list ‘(2 4) ‘(b c)) is '(2 b 4 c). Here's what I have so far, but when I compile I am receiving the "application:not a procedure" error
(define (merge-list lst1 lst2)
(cond ((null? lst1) lst2)
((null? lst2) lst1))
(append( append(list(car lst1) list(car lst2)))list-shuffle((cdr lst1)(cdr lst2))))

The solution is simpler than you think, we don't even have to use append - in fact, you should avoid using append, whenever possible use cons for building an output list: this is because append does more work and can potentially lead to O(n^2) solutions. Try this instead:
(define (merge-list lst1 lst2)
(cond ((null? lst1) lst2) ; if the first list is empty, return the second
((null? lst2) lst1) ; if the second list is empty, return the first
(else (cons (car lst1) ; otherwise `cons` the first element of the first list
(merge-list lst2 (cdr lst1)))))) ; and interleave the lists
It works as expected for lists of the same length:
(merge-list '(2 4) '(b c))
=> '(2 b 4 c)
(merge-list '(2 4 6) '(b c d))
=> '(2 b 4 c 6 d)

Related

behavior differently with two input lists with same length vs. with different lengths (Scheme)

the code "tsFunc" gets two lists as input and it will pairs each elements from two lists.
It works most of cases.
but then I find a bit strange behavior when I give 2 equal length of lists (e.g. '(1 2) '(3 4).... or '(a b c) '(1 2 3).... , it works strangely. first, here are code.
[problem 1]
(define (tsFunc lst1 lst2)
(define (helper ls1 ls2 rst)
(reverse (if (or (null? ls1) (null? ls2))
rst
(helper (cdr ls1) (cdr ls2)
(cons (cons (car ls1) (car ls2)) rst)))))
(helper lst1 lst2 '()))
the behavior like this:
1) correct behavior with uneven length of lists :
(tsFunc '(1 2 3) '(a b)) ====> output: ((1 . a) (2 . b))
2) strange behavior with even length of lists
: (tsFunc '(1 2 3) '(a b c)) ===> output (wrong): ((3 . c) (2 . b) (1 . a))
===> expected : ((1 . a) (2 . b) (3 . c))
when the two input lists are same length, what is happening?
do the tsFunc logic have different behavior between the input lists with same lengths vs. the input lists with different lengths?
(Note. as I know, the code needs to have "reverse" for the final result. so it is not because of "reverse" in the code)
[problem 2] with the result of tsFunc => tsFunc result: (1 . 2) (3 . 4) => try to implement product like this (1*2)+(3*4) = 14, so I have like this..
(define (func l1 l2)
(tsFunc (l1 l2) ;; line 2 - how to call tsFunc's result??
(foldl (lambda (acc pair) ;; line 3
(+ acc (* (car pair) (cdr pair)))) ;; line 4
'()
l1 l2))) ;; like this?? or ??
line 3 , 4 ok..that's the logic what to do, then, how to call tsFunc result to use it as input and.. two lists for the last line.. unclear..
The first problem is that you keep reversing the lists at each iteration, if you really need to reverse the output, do it just once at the end:
(define (tsFunc lst1 lst2)
(define (helper ls1 ls2 rst)
(if (or (null? ls1) (null? ls2))
(reverse rst)
(helper (cdr ls1) (cdr ls2)
(cons (cons (car ls1) (car ls2)) rst))))
(helper lst1 lst2 '()))
Now, for the second problem - the code doesn't even compile: you're not correctly calling the tsFunc procedure, and you're calling it in the wrong point. Also the initial value for the accumulator parameter is wrong - you can't use a list if you intend to return a number:
(define (func l1 l2)
(foldl (lambda (acc pair)
(+ acc (* (car pair) (cdr pair))))
0
(tsFunc l1 l2)))
Using the sample input in the question, here's how it would work:
(func '(1 3) '(2 4))
=> 14
In the above tsFunc takes '(1 3) and '(2 4) as inputs, transforming them into '((1 . 2) (3 . 4)) and then foldl preforms the operation (1*2)+(3*4) = 14, as expected.
Since you are allowed to use higher order functions, why not use just SRFI-1 List library fold?
#!r6rs
(import (rnrs base)
(only (srfi :1) fold)) ;; srfi-1 fold stop at the shortest list
(define (func lst1 lst2)
(fold (lambda (x y acc)
(+ acc (* x y)))
0
lst1
lst2))
(func '(1 3) '(2 4 8)) ; ==> 14

Improper vs. proper list in Scheme

The original code I try to implement.. the output should be (1.4) (2.5) from my code.. I think you all know what I try to do....this is also tail recursion practice
my code
(define (myFunc lst1 lst2)
(if (or (null? lst1) (null? lst2))
'()
(list (cons (car lst1) (car lst2))
(myFunc (cdr lst1) (cdr lst2)))
))
after several of you gave me good advice about cons-pair.. so now it get's the dotted symbol in the middle.. then problem is that the improper list with empty list in the end..
when 2 input lists are like this ..... '(1 2 3 4) '(4 5 6))
my output is like this ; ((1 . 4) ((2 . 5) ((3 . 6) ())))
the empty list in the end of output shouldn't be there... so I couldn't understand about improper list , proper list....? is there are any document, I can look at?
Consider the difference between cons and list:
That is, (cons a b) creates a cell whose car is a and cdr is b.
(list a b) creates a cell whose car is a, but the cdr is a list, and the car of that list is b, while its cdr is nil.
If b is a list, the one on the left will be a list which has b as its tail, and with a added at the front of b.
The one on the right will also be a list, but one which has b as its second element, not as its tail like you want.
To fix your program, you only need to replace your list with a cons.
But your function is not tail-recursive, because it does things with the result of the recursive call.
To make it tail-recursive, a good way is usually to make a helper function which has an accumulator parameter.
I would probably write it something like this:
(define (zip-cars l1 l2)
(cons (car l1) (car l2)))
(define (zip-help l1 l2 result)
(if (or (null? l1) (null? l2))
result
(zip-help (cdr l1) (cdr l2) (cons (zip-cars l1 l2) result))))
(define (zip l1 l2)
(zip-help l1 l2 '()))
Just replace list with cons. Then your code will evaluate to `(cons (cons (cons .... (cons ... '())) and your list will be properly terminated.
(define (zip lst1 lst2)
(if (or (null? lst1) (null? lst2))
'()
(cons (cons (car lst1) (car lst2))
(zip (cdr lst1) (cdr lst2)))))
then
(zip '(1 2 3 4) '(4 5 6))
=> '((1 . 4) (2 . 5) (3 . 6))
This is not tail-recursive, though, since after returning from zip the consing still has to be done.
EDIT
An example of a tail-recursive version:
(define (zip lst1 lst2)
(let loop ((lst1 lst1) (lst2 lst2) (res '()))
(if (or (null? lst1) (null? lst2))
(reverse res)
(loop (cdr lst1)
(cdr lst2)
(cons (cons (car lst1) (car lst2)) res)))))

Comparing individual elements of two lists of the same length in DrRacket

I am trying to write a function that takes two lists (must be of equal length) and then goes through each list comparing individual items.
For example: (1 2 3) and (2 4 5) would return true because each element of list 2 is greater than the corresponding element in list 1. (1 2 3) and (0 4 1) would return false as would (1 2 3) and (1 2 3 4) since they are of different size. Using Dr Racket
(define (each-bigger? a-lon another-lon)
(cond
(if
[(= (length a-lon) (length another-lon))true]
(then
[(> (first a-lon) (first another-lon))true]
(then
[(> (rest a-lon) (rest another-lon))true]
[else false])))))
this didn't work.
Unfortunately you've got both your syntax and your logic wrong. I believe your intention was to write something like this:
(define (each-bigger? lst1 lst2)
(cond
((and (null? lst1) (null? lst2)) #t) ; both lists are empty => true
((or (null? lst1) (null? lst2)) #f) ; only one is empty => not the same length => false
((>= (car lst1) (car lst2)) #f) ; first element of lst1 >= first element of lst2 => false
(else (each-bigger? (cdr lst1) (cdr lst2))))) ; recur on the rest of the list
which can be shortened to
(define (each-bigger? lst1 lst2)
(or (and (null? lst1) (null? lst2)) ; EITHER both lists are empty
(and (not (or (null? lst1) (null? lst2))) ; OR 1) none of them is empty
(< (car lst1) (car lst2)) ; 2) AND first element of lst1 < first element of lst2
(each-bigger? (cdr lst1) (cdr lst2))))) ; 3) AND each-bigger? is true for the rest of both lists
Hope this helps!
Clearly you want to implement a solution from scratch, and #uselpa's advice is spot-on. But in a non-academic context you should use existing procedures for solving this kind of problem, in particular andmap is your best friend here:
(define (each-bigger? lst1 lst2)
(and (= (length lst1) (length lst2))
(andmap < lst1 lst2)))
The trick is that andmap applies a predicate on elements of both lists, passing as parameters the first element of lst1 and the first element of lst2, then the second element of lst1 and the second element of lst2, and so on (BTW, andmap accepts one or more lists as parameters, as long as the predicate receives the same number of parameters).
If all the applications of the predicate return #t then #t is returned, if a single predicate returns #f then evaluation stops and #f is returned. In the above example, the predicate is just <, applied pair-wise between the two lists. It works as expected:
(each-bigger? '(1 2 3) '(2 4 5))
=> #t
(each-bigger? '(1 2 3) '(0 4 1))
=> #f
(each-bigger? '(1 2 3) '(2 4 5 6))
=> #f

Scheme : Make operations on a list without changing its copy?

I have a helper to copy a list :
(define (list-copy list)
(if (null? list)
'()
(cons (car list) (list-copy (cdr list)))))
Then,
(define (multList lst1 lst2)
(define lstCopy2 (list-copy lst2))
(cond ((null? lst1) ())
((eq? (length lst1) (length lst2)) (cons (* (car lst1) (car lst2)) (multList (cdr lst1) (cdr lst2))))
((> (length lst1) (length lst2))
(if (null? lst2) lstCopy2
(cons (* (car lst1) (car lst2)) (multList (cdr lst1) (cdr lst2)))))
(else '())))
I'm trying to copy lst2 into lstCopy2 and then I would like lstCopy2 to stay intact when I'm working on lst2 in order to call lst2 (with the help of lstCopy2) as it was at first.
In my 3rd cond (when lenght lst1 > lenght lst2) when lst2 = () I would like to continue the process until lst1 is ().
Thanks for your help
As far as I can see your copy is not used. In addition, none of the procedure mutates anything so (equal? lst2 lstCopy2) will always be #t for every recursion / element of the list.
If lst1 is shorter than lst2 or you've reached the end of the list you will get an error since () is an illegal expression. perhaps you meant '()?
This could have been written a lot easier:
(require srfi/1)
(define (multList lst1 lst2)
(define (aux lst1 lst2)
(if (null? lst2)
'()
(cons (* (car lst1)
(car lst2))
(aux (cdr lst1) (cdr lst2)))))
(aux (apply circular-list lst1) lst2))
(multList '(1 -1) '(1 2 3 4 5 6)) ; ==> (1 -2 3 -4 5 -6)
;; with srfi-1-version of map we can use it to make the code shorter
(define (multList lst1 lst2)
(map * (apply circular-list lst1) lst2))
You're going about this in a very odd way. The standard way to do this is the define an inner function. Usually you inner function and then call it.
The way you were doing it you were making a copy of lst2 every time you called multList, which is not what i think you want.
But I don't see where you actually reference the original 2nd list so I don't see the reason behing what you want to do.
(define (multList oL1 oL2)
(define (helper lst1 lst2)
(cond ((null? lst1) '())
((null? lst2) (helper lst1 oL2))
(else
(cons (* (car lst1) (car lst2))
(helper (cdr lst1) (cdr lst2))))))
(helper oL1 oL2))
(multlist '(9 2 4) '(1 2))
;Value 14: (9 4 4)
(multlist '(1 2) '(9 2 4))
;Value 15: (9 4)
See what I mean about not really being a proper multiplication? (multist a b) is not always the same as (multlist b a).

Scheme: adding 2 lists by index

I need to write a function in Scheme (Racket) that takes two not necessarily equal
length lists and return a list which each element is the sum of the elements of the same
index from the two lists. if the lists' length is not equal the shorter one should append to itself until it reaches the size of the longer one. for example:
=> (addLists '(1 2 3 4) '(1 2))
(2 4 4 6)
=> (addLists '(1 2 3 4) '(1 2 3 4 5))
(2 4 6 8 6)
Until now I was able to write a function that completes this for equal length lists, but the problem lies with how do I increase the length of the shorter list within this function (or with a helper function that gets a list and a size and extends it properly).
(define (sumListPairs lst1 lst2)
(if (null? lst1) null
(cons (+ (car lst1) (car lst2))
(sumListPairs (cdr lst1) (cdr lst2)))))
Will appreciate any help, Thank you.
This can be done, but since I have the impression that this is a homework exercise, I'll only give a hint. First, introduce a named-let to do the actual recursion. Then, expand the number of cases in the recursion from two to four.
(define (sumListPairs lst1 lst2)
(let loop ((l1 lst1) (l2 lst2))
(cond ((and (null? l1) (null? l2)) null)
((null? l1) ...)
((null? l2) ...)
(else (cons (+ (car lst1) (car lst2))
(loop (cdr l1) (cdr l2)))))))
Now, fill in the ... parts. Note that you have access to all of l1, l2, lst1 and lst2. (You might want to refactor a bit after you're done, since the cases will be quite similar.)