Return alternate elements of 3 given lists. Scheme - scheme

This procedure is supposed to return a list with alternative values from 3 given lists. So for example (alt ('a b c)'(1 2 3)'(i j k)) should return '(a 1 i b 2 j c 3 k).
This is my logic so far. I would take the first element of each list and recursively call the procedure again with cdr as the new arguments.
(define (alternate lst1 lst2 lst3)
(cons (car lst1)
(cons (car lst2)
(cons (car lst3)
(alternate (cdr lst1)(cdr lst2)(cdr lst3))))))
The error occurs in
(cons (car lst1)
"mcar: contract violation
expected: mpair?
given()"
(cons a d) returns a newly allocated pair whose first element is a and second element is d. But since there are 3 not 2 given lists, is there another way to approach creating lists?
Would this be another approach?
(define (alternate lst1 lst2 lst3)
(list (car lst1)(car lst2)(car lst3))
(alternate (cdr lst1)(cdr lst2)(cdr lst3)))

You need to add empty list check to avoid the error. So your code should look like this:
(define (alternate lst1 lst2 lst3)
(if (or (null? lst1) (null? lst2) (null? lst3))
'()
(cons (car lst1)
(cons (car lst2)
(cons (car lst3)
(alternate (cdr lst1)(cdr lst2)(cdr lst3)))))))
If you can use SRFI-1 (or more precisely append-map), then you can also write like this:
(define (alt l1 l2 l3) (append-map list l1 l2 l3))

You can just use the following standard Scheme:
(define (alternate . lists)
(apply append (apply map list lists)))
Not very optimized, but does the job :)
Eval: http://eval.ironscheme.net/?id=175

Related

Remove all duplicates from a list in scheme [duplicate]

This question already has an answer here:
Removing all duplicate members from a list in scheme
(1 answer)
Closed 4 years ago.
Write a SCHEME function remove-duplicates that removes all duplicates from a list. (Hint: you might start by defining a function which removes all duplicates of a particular given value v from a list; then what?)
Example:
(remove-duplicates ’(1 2 3 4 5 3 1)) should produce
’(1 2 3 4 5)
I have this so far:
(define (remove v l)
(if (null? l)
l
(if (equal? v (car l))
(cdr l)
(cons (car l)
(remove v (cdr l))))))
(define (remove-duplicates l)
(cond ((null? l) '())
((null? (cdr l)) l)
((equal? (car l) (car (cdr l)))
(remove (cdr (cdr l)) (remove-duplicates (cdr (cdr l)))))
(else (cons (car l) (remove-duplicates (cdr l))))))
The whole point of abstraction is that you can have simpler code that does some of the job which is testable. Have you tested remove on its own?
(remove 'a '(g a b c a b c a))
; ==> (g b c a b c a)
So when it find one match the rest of the list is (cdr l). Are you just expecting one duplicate? This is the most important part of your solution.
When it comes to remove-duplicates you do too much. When the list is not empty the first element is the first element of the result consed with the recursion with the argument being the rest of argument with the first element removed. ie. (cons (car l) (remove-duplicates (remove (car l) (cdr l)). No more comparing necessary.

Racket find shared elements between lists

I'm trying to create a specific response for a given list if it has shared elements with another list. As in if I have a list that is (My name is John) and I have another list of (John Adam Jacob) I would want the first list to be able to see that John is in the second list, and be able to print something along the lines of (this is a known name) or something similiar.
The code I have thought of uses map, and member.
(define (specific-reply user-list)
(cond (member (map (lambda (user-list)) '(John Adam Jacob)))
(write (this is a known name))
(else
(write (this is not a known name)))))
I'm extremely knew to both racket and scheme however and I haven't really gotten it to compile yet so I think I'm largely off.
Any help would be greatly appreciated.
You don't need to complicate the problem if your task is to just find if a is a member of (a b c),
Here's a piece of Scheme code that can tell if a is a member of lat.
It's just a simple recursive function that compares each element of lat with a for a match.
(define member?
(lambda (a lat)
(cond
((null? lat) #f)
((eq? a lat) #t)
(else
(member? a (cdr lat))))))
If you want to take this further and find the intersection of two lists, we can do something like this!
(define intersect
(lambda (set1 set2)
(letrec
((I (lambda (set)
(cond
((null? set) (quote ()))
((member? (car set) set2)
(cons (car set)
(I (cdr set))))
(else (I (cdr set)))))))
(I set1))))
You can use this code as such. Tested from guile compiler
(begin
(display (intersect `(1 2 3) `(1 3 4 5 2)))
(newline))
>> (1 2)
EDIT
I recommend you read The Little Schemer and the The Seasoned Schemer to get more familiar with these kind of concepts
Why not use set in racket:
(define (list-intersect-2 lst1 lst2)
(set->list
(set-intersect (list->set lst1)
(list->set lst2))))
For a solution that takes one or more lists:
(define (list-intersect lst1 . lstn)
(set->list
(foldl set-intersect
(list->set lst1)
(map list->set lstn))))
(list-intersect '(1 2 3) '(2 3 4) '(3 4 8))
; ==> (3)
One can also use built-in functions filter and member to find intersection of 2 lists:
(define (intersection l1 l2)
(remove-duplicates
(filter (λ (x) (member x l1))
l2)))
Above checks each item of l2 to keep it only if it is a member of l1 also.
One can also use for/list to check each element and return a list of common items:
(define (intersect l1 l2)
(remove-duplicates
(for/list ((i l1)
#:when (member i l2))
i)))
Both above function remove duplicates. Just avoiding use of remove-duplicates may result in different result if simply the order of l1 and l2 is interchaged. If one wants that the repeated elements to come repeatedly in outcome list, one can use following function in which common items are removed before proceeding:
(define (intersection2 l1 l2)
(let loop ((l1 l1)
(l2 l2)
(ol '()))
(cond
[(empty? l1) (reverse ol)]
[(member (first l1) l2) ; first item of l1 is common
(loop (rest l1) ; loop with rest of l1
(remove (first l1) l2) ; remove common item from l2
(cons (first l1) ol))] ; add common item to outlist
[else
(loop (rest l1)
l2
ol)])))
Testing:
(intersection2 '(2 4 2 7 2 10) '(10 2 9 2 0 11))
Output:
'(2 2 10)

How to reverse nested lists in Scheme

Consider:
(define (nested-reverse lst)
(cond ((null? lst) '())
((list? (car lst)) (nested-reverse (car lst)))
(else
(cons (nested-reverse (cdr lst))
(list (car lst))))))
When I input,
(nested-reverse '((a b c) 42))
it gives me ((() 42) (a b c)). It's supposed to give me (42 (c b a)). How I would change my code so that the nested lists also get reversed?
Keep in mind that a list (1 2 3) is (cons 1 (cons 2 (cons 3 '()))). Using append is a very poor choice on how to reverse a list since append is implemented like this:
(define (append lst1 lst2)
(if (null? lst1)
lst2
(cons (car lst1) (append (cdr lst1) lst2))))
A list can be iterated from the first element towards the end while it can only be made in reverse. Thus the obvious none recursive reverse would look like something like this:
(define (simple-reverse lst)
(let loop ((lst lst) (result '()))
(if (null? lst)
result
(loop (cdr lst) (cons (car lst) result)))))
To make it work for nested list you check if you need to reverse (car lst) by checking of it's a list or not and use the same procedure as you are creating to do the reverse on the element as well. Other than that it's very similar.

Lists traversal in Scheme

myList is a list with elements both as symbols or lists of the same type of myList.
For example: myList = '(a b (a d c) d ()) , etc.
I want to write a function in Scheme which would just traverse it (eventually I will replace the symbols with other values).
I wrote this function:
(define traversal (lambda (myList)
(if (null? myList) '()
(if (and (list? (car myList)) (not (null? (car myList))))
(list (traversal (car myList)) (traversal (cdr myList)))
; else if car is an empty list
(if (null? (car myList))
(list (traversal (cdr myList)))
; else car is a symbol
(append (list (car myList)) (traversal (cdr myList))))))))
It gives correct results for some configuration of myList, but definitely it is not the one.
For example,
(display (traversal '((f) h (r t b) (x m b m y) b (c (d)))))
adds additional paranthesis which I don't need.
What would be a correct way to display such a list?
You're testing null? in so many places, where one test is generally enough.
You rarely use list in these traversals, but simply cons.
Also, append is best avoided, and not needed here.
Repetitive use of (car ...) is optimised with a let form.
The simplified form of your code would be:
(define traversal
(lambda (myList)
(if (null? myList)
'()
(let ((c (car myList)))
(cons (if (list? c) (traversal c) c)
(traversal (cdr myList)))))))
EDIT
While this procedure works well for proper lists, it doesn't correctly work for improper lists (although it appears to). The following is a more general approach that works for every kind of S-expression, including proper lists, and I recommend this over the previous code:
(define traversal
(lambda (sexp)
(cond
((null? sexp) '())
((pair? sexp) (cons (traversal (car sexp))
(traversal (cdr sexp))))
(else sexp))))
You are close to the solution. Here are a few hints:
Instead of nested ifs try using the cond form, it is more readable.
The expression (and (list? (car myList)) (not (null? (car myList)))) is correct, but you may use (pair? (car myList)) which is shorter and does almost the same thing.
traversal should return a list but using list with list arguments here
(list (traversal (car myList)) (traversal (cdr myList)))
will return a list of lists. E.g. (list '(a) '(b)) will return ((a) (b)) instead of (a b). In these cases you should use append (append '(a) '(b)) -> (a b).
If a value is not a list but you want to add it to an existing list, use the cons procedure.
(cons 'a '(b c)) -> (a b c).

Scheme Deep reverse function

I am doing a scheme program which takes in a list and then reverse it. So far it works for simple list, which does not contain any sublist, but when I test it for a list contains sublist, it fails. Please help me where is wrong with it.
Here is the code:
(define deep-reverse
(lambda (L)
(cond
((empty? L) '())
(else (append (deep-reverse (rest L)) (list (first L)))))))
(define (deeprev L)
(if (null? L) '()
(if (list? (car L))
(if (chek (car L)) (append (deeprev (cdr L)) (list (reverse (car L))))
(append (deeprev (cdr L)) (list (deeprev (car L)))))
(append (deeprev (cdr L)) (list (car L))))))
First of all, you are using undefined Scheme functions. I am going to work off the following assumptions:
empty? is null?
rest is cdr
first is car
Your code works by taking the first element in a list and adding it to another list. However, that first element of a list can be a list itself. You need to test to see if the element that you're working on is atomic or a list. If it's a list, then you call deep-reverse recursively.
If you would like to see code appended to this, leave a comment.

Resources