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

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).

Related

Merge two list randomly returns a strange merged list

I've just started to learn Racket and I need to create a procedure that merge two list randomly.
This is my code:
#lang racket
(define merge-randomly
(lambda (lst1 lst2)
(cond ((and (null? lst1) (null? lst2)) null)
((null? lst1) lst2)
((null? lst2) lst1)
(else
(cond ((> (random) 0.5) (cons (cons (car lst1) (car lst2)) (merge-randomly (cdr lst1) (cdr lst2))))
(else (cons (cons (car lst2) (car lst1)) (merge-randomly (cdr lst1) (cdr lst2))))
)
)
)
)
)
I need to use with list like these two:
(define l1 '((1 2 3) (7 8 9)))
(define l2 '((4 5 6)))
I need to create a new list like this one:
'((4 5 6) (1 2 3) (7 8 9))
But I get this list:
'(((4 5 6) 1 2 3) (7 8 9))
I'm doing something wrong, probably here, (cons (cons (car lst1) (car lst2)), or here, (cons (cons (car lst2) (car lst1)), at the else instruction in first cond.
How can I get the list I want to get?
Your guess is correct. The format for cons is this:
(cons first-element rest-of-the-list)
So, when you use (const '(4 5 6) '(1 2 3)), it returns ((4 5 6) 1 2 3).
The correct format for what you are trying to do would be:
(cons (car lst1) (cons (car ls2) (merge-randomly (cdr lst1) (cdr lst2))))
and similarly for the second case.
Here's what the final function should look like:
(define merge-randomly
(lambda (lst1 lst2)
(cond ((and (null? lst1) (null? lst2)) null)
((null? lst1) lst2)
((null? lst2) lst1)
(else
(cond ((> (random) 0.5) (cons (car lst1) (cons (car lst2) (merge-randomly (cdr lst1) (cdr lst2)))))
(else (cons (car lst2) (cons (car lst1) (merge-randomly (cdr lst1) (cdr lst2)))))
)
)
)
)
)
The problem is with (cons (cons (car lst1) (car lst2)) ...). Change it to (cons (car lst1) (cons (car lst2) ...).
PS Your closing parentheses are not idiomatically placed.

Flattening a list in scheme

I'm attempting to create a function for flattening lists in the R5RS language in scheme and am experiencing the issue where my function simply returns the input list without removing the parenthesis. I figured this was due to the extra cons, but when I remove it the output becomes the list without the elements that were in the parenthesis. Can someone point me in the right direction?
(define (denestify lst)
(cond ((null? lst)'())
((list? (car lst))(cons (denestify (cons (car (car lst))(cdr (car lst))))
(denestify (cdr lst))))
(else (cons (car lst)(denestify (cdr lst))))))
This shows how to convert Óscar López answer into one that doesn't use append and is also tail recursive:
(define (denestify-helper lst acc stk)
(cond ((null? lst)
(if (null? stk) (reverse acc)
(denestify-helper (car stk) acc (cdr stk))))
((pair? (car lst))
(denestify-helper (car lst) acc (cons (cdr lst) stk)))
(else
(denestify-helper (cdr lst) (cons (car lst) acc) stk))))
(define (denestify lst) (denestify-helper lst '() '()))
(denestify '(1 (2 (3 4 (5) (6 (7) (8)) (9))) 10))
Note how it uses the accumulator to build up the list in reverse and also a list as a stack.
Which results in
'(1 2 3 4 5 6 7 8 9 10)
as expected.
After I posted this I thought of this change:
(define (denestify-helper lst acc stk)
(cond ((null? lst)
(if (null? stk) (reverse acc)
(denestify-helper (car stk) acc (cdr stk))))
((pair? (car lst))
(denestify-helper (car lst) acc (if (null? (cdr lst))
stk
(cons (cdr lst) stk))))
(else
(denestify-helper (cdr lst) (cons (car lst) acc) stk))))
Which eliminates some useless consing by effectively doing tail-call optimization on our stack. One could go further and optimize handling of one element lists.
If you want to flatten a list of lists, then you have to use append to combine each sublist. Besides, your implementation is overly complicated, try this instead:
(define (denestify lst)
(cond ((null? lst) '())
((pair? (car lst))
(append (denestify (car lst))
(denestify (cdr lst))))
(else (cons (car lst) (denestify (cdr lst))))))
For example:
(denestify '(1 (2 (3 4 (5) (6 (7) (8)) (9))) 10))
=> '(1 2 3 4 5 6 7 8 9 10)

boolean function for a sublist in scheme

I need make a boolean function for evaluating two list,for example:
(define list1 '((1 2) (4 5) (8 6) (2 8)))
(define list2 '((1 2) (8 6)))
list2 is a sublist of list1, and must returned #t, but I don't know how do it, I try with this function for comparing two list
(define (sublist? lst1 lst2)
(if (null? lst2)
#f
(if(list? (car lst2))
(sublist? lst1 (car lst2))
(if (and(equal? car(lst1) (car lst2)) (equal? cdr(lst1) (car lst2)))
#t (sublist? lst1 (cdr lst2))))))
help :(
This sublist? behaves as a "subset?".
; sublist? : list list -> "boolean"
; return non-false if all elements of xs are in ys
(define (sublist? xs ys)
(or (null? xs) ; the empty list is a sublist of ys
(and ; for a non-empty list
(member (car xs) ys) ; the first element must be in ys
(sublist? (cdr xs) ys)))) ; and the rest of the elements as well.
This sublist? behaves as a "substring?"
; prefix? : list list -> boolean
; is xs a prefix of ys?
(define (prefix? xs ys)
(or (null? xs)
(and (equal? (car xs) (car ys))
(prefix? (cdr xs) (cdr ys)))))
; sublist? : list list -> boolean
; is xs a consecutive sublist of ys?
(define (sublist? xs ys)
(or (null? xs)
(prefix? xs ys)
(and (not (null? ys))
(prefix? xs (cdr ys)))))
A suggested solution:
(define list1 '((1 2) (4 5) (8 6) (2 8)))
(define list2 '((4 5) (8 6)))
(define (sublist? lst1 lst2)
(if (null? lst2)
#t
(if (and (null? lst1)
(not (null? lst2)))
#f
(if (list? (car lst2))
(or (and (sublist? (car lst1) (car lst2))
(sublist? (cdr lst1) (cdr lst2)))
(sublist? (cdr lst1) lst2))
(if (eq? (car lst1) (car lst2))
(sublist? (cdr lst1) (cdr lst2))
(sublist? (cdr lst1) lst2))))))
(sublist? list1 list2)
Explanation:
This is (not) simply handling all the edge-cases:
- If list2 is null - it is always a sublist of list1
- If we got to the end of list1 and list2 is not yet found - return false
- If (car list2) is a list - we need to check recursively two cases: if (car list1) equals to (car list2) or if (car list2) is somewhere else in (cdr list1)
- If (car list1) and (car list2) are the same - we'll check recursively with the rest of both lists: (cdr lst1) and (cdr lst2)
This answer was tested here

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

How to make pairs from a numeric list based on cardinality?

I have a list '(1 2 1 1 4 5) and want output list as '((1 3)(2 1)(4 1)(5 1)). I have written a small code but I am stuck with how to calculate the cardinality for each number and then put it as pair in list. Can anyone please look at my code and give some ideas?
(define set2bags
(lambda (randlist)
(cond ((null? randlist) '())
(else
(sort randlist)
(makepairs randlist)))))
(define makepairs
(lambda (inlist)
(let ((x 0)) ((newlist '()))
(cond ((zero? (car inlist)) '())
(else
(eq? (car inlist)(car (cdr inlist)))
(+ x 1)
(makepairs (cdr inlist))
(append newlist (cons (car inlist) x)))))))
Your current solution is incorrect - it doesn't even compile. Let's start again from scratch, using a named let for traversing the input list:
(define set2bags
(lambda (randlist)
(cond ((null? randlist) '())
(else (makepairs (sort randlist >))))))
(define makepairs
(lambda (inlist)
(let loop ((lst inlist)
(prv (car inlist))
(num 0)
(acc '()))
(cond ((null? lst)
(cons (list prv num) acc))
((= (car lst) prv)
(loop (cdr lst) prv (add1 num) acc))
(else
(loop (cdr lst) (car lst) 1 (cons (list prv num) acc)))))))
Now it works as expected:
(set2bags '(1 2 1 1 4 5))
=> '((1 3) (2 1) (4 1) (5 1))
The trick is keeping a counter for the cardinality (I called it num), and incrementing it as long as the same previous element (I named it prv) equals the current element. Whenever we find a different element, we add a new pair to the output list (called acc) and reset the previous element and the counter.
Your code is fairly hard to read without proper formating.
I notice a two branch cond, which is easier to read as an if.
In your else clause of set2bags, you call (sort randlist) but leave it as is. You actually want to use this in the next s-expression (makepairs (sort randlist))
So far a pretty good idea.
Now in makepairs you should have better abstraction, say let variables like-first and unlike-first. If the inlist is null, then the function should be the null list, else it's the pair with the car being the list of the car of like-first and the length of like-first and the cdr being the result of calling makepairs on the unlike-first list
(define (makepairs inlist)
(let ((like-first (filter (lambda (x) (equal? x (car inlist)) inlist))
(unlike-first (filter (lambda (x) (not (equal? x (car inlist))) inlist)))
(if (null? inlist)
'()
(cons (list (car inlist) (length like-first)) (makepairs unlike-first)))))
more effecient version
(define (makepairs inlist)
(if (null? inlist)
'()
(let loop ((firsts (list (car inlist)))
(but-firsts (cdr inlist)))
(if (or (null? but-firsts)
(not (equal? (car firsts) (car but-firsts))))
(cons (list (car firsts) (length firsts))
(makepairs but-firsts))
(loop (cons (car but-firsts) firsts) (cdr but-firsts))))))
]=> (makepairs (list 1 1 1 2 4 5))
;Value 17: ((1 3) (2 1) (4 1) (5 1))
If you have your own implementation of sort, say a mergesort you could write this right into the merge part for the best effeciency.
(define (set2bags lst)
(mergesort2bags lst <))
(define (mergesort2bags lst pred)
(let* ((halves (divide-evenly lst))
(first-half (car halves))
(other-half (cadr halves)))
(cond ((null? lst) '())
((null? (cdr lst)) (list (list (car lst) 1)))
(else
(merge-bags
(mergesort2bags first-half pred)
(mergesort2bags other-half pred)
pred)))))
(define (divide-evenly lst)
(let loop
((to-go lst)
(L1 '())
(l2 '()))
(if (null? to-go)
(list L1 L2)
(loop (cdr to-go) (cons (car to-go) L2) L1))))
(define (merge-bags L1 L2 pred)
(cond ((null? L1) L2)
((null? L2) L1)
((pred (caar L1) (caar L2))
(cons (car L1) (merge-bags (cdr L1) L2 pred)))
((equal? (caar L1) (caar L2))
(cons (list (caar L1) (+ (cadar L1) (cadar L2)))
(merge-bags (cdr L1) (cdr L2) pred)))
(else (cons (car L2) (merge-bags L1 (cdr L2) pred)))))
(mergesort2bags (list 1 2 1 1 4 5) <)
;Value 46: ((1 3) (2 1) (4 1) (5 1))
I'm thinking for very large datasets with a lot of repetition this method would pay off.