Remove match elements from list using Scheme - scheme

I am trying to write a function which takes in two lists, L1 and L2, and returns a list which contains all of L1 except for the elements which are also found in L2.
Example: Pass in '(1 2 3) '(3 4 5) and the return should be '(1 2)
I have written a helper function called removeOne which is working perfectly fine:
(define (removeOne x L)
(cond ((null? L) '())
((= (car L) x) (removeOne x (cdr L)))
(#t (cons (car L) (removeOne x (cdr L))))))
My issue is with the main function which is supposed to use removeOne to get rid of all matching elements from L1. I have written this so far:
(define (removeAll L1 L2)
(cond ((null? L1) '())
((null? L2) '())
((= (car L1) (car L2)) (removeOne (car L2) L1))
(#t (removeAll (cdr L1) L2))))
This is currently returning () no matter what lists I use as input.
I feel like I'm close to getting this to work. Any help would be greatly appreciated!

I have hard time following your logic in removeAll. Since you have written a removeOne, shouldn't you just call removeOne with all elements of L2?
Besides, this condition
((null? L2) '())
is strange.
You are supposed to return all elements of L1 that are not in L2. And L2 is empty. So, all elements of L1 that are not in '()... how can this be the empty list? No elements are in (). So, "all elements of L1 that are not in ()" is just a convoluted way to say "L1". So, clearly, case (null? L2) should be associated to result L1.
So, if I summarize the recursion of removeAll, what you want to do is remove (car L2) from L1, then remove all of (cdr L2) from that result (or the other way, it doesn't really matter). Unless L2 is empty, in which case, removeAll has nothing to remove.
So
(define (removeAll L1 L2)
(if (null? L2)
L1
(removeAll (removeOne (car L2) L1) (cdr L2))))
Or,
(define (removeAll L1 L2)
(if (null? L2)
L1
(removeOne (car L2) (removeAll L1 (cdr L2)))))
(same result. The 1st one remove first (car L2) from L1, then remove (cdr L2) from the result. The second one remove first (cdr L2) from L1, then remove (car L2) from the result. In other words, the 1st one remove one by one elements of L2 from L1, in the normal order, while the second one does it in reverse order.

There are a few atomic functions for searchcing lists, like member, that you can use. Using such a function you will reduce your problem to a recursive function with 3 cases: null, match and otherwise. Depending on your interest to compare objects, you will use member or other one, they use all a different equality operator.

Related

Trying to append recursively, what am I doing wrong in Scheme?

Trying to recursively append every element from list a to list c. Currently only one elements gets appended. What am I doing wrong? I', trying to reverse a list. But currently stuck understanding how to even append a list to another list.
(define a '(1 2 3))
(define c '())
(define fun
(lambda (() l1) l1
(l l1) (append l1 (car l)) (fun (cdr l) l1)
))
(fun a c)
I'm using a scheme like interpreter, where I cannot use any new built-in functions except of the listfunctions.
You need to use
(lambda (l l1)
(if (null? l)
l1
(append l1 (car l)) (fun (cdr l) l1)))
what you wrote looks like it would work if there was a pattern matching facility, but our lambda is more basic and doesn't pattern match.

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)

Sort a list in scheme

I want to create function which sorts list. For example I have this list:
x1, x2, x3 .... xn
or
1, 2, 3, 4, 5, 6
I want to display the numbers in this order:
x1, xn, x2, xn-1
or
1, 6, 2, 5, 3, 4
Can you help me to write this example?
Usually when we talk about sorting, we refer to ordering the items by some characteristic of the item contents, not the item position in the list. I would call your situation permuting, but perhaps some people might dispute that usage, too. :-)
Here's how you might approach the problem:
Split the list in the middle (you can do this using tortoise-and-hare if you only want to traverse the list once); call those lists head and tail, if you want.
Reverse the tail list, and interleave it with the head list.
Another approach:
Reverse the original list pairs (let's call it rev).
Interleave the original list with rev, keeping track of the element traversed each time. When they meet in the middle, stop.
Here's a demonstration of the second approach (requires SRFI 1 to be loaded):
(define (zippy lst)
(if (null? lst)
'()
(let recur ((lst lst)
(rev (pair-fold cons '() lst)))
(cond ((eq? lst (car rev)) (list (car lst)))
((eq? (cdr lst) (car rev)) (list (car lst) (caar rev)))
(else (cons* (car lst) (caar rev)
(recur (cdr lst) (cdr rev))))))))
This is not really a sorting operation, more like a shuffling; here's another way to solve it. First, let's define the interleave procedure that alternates elements from two lists, returning a single list:
(define (interleave l1 l2)
(cond ((empty? l1) l2)
((empty? l2) l1)
(else (cons (first l1)
(interleave l2 (rest l1))))))
Now we take the original list and split-at the middle (this is a Racket-specific procedure); finally we interleave the two resulting lists, reversing the tail:
(define (zippy lst)
(let-values (((head tail) (split-at lst (quotient (length lst) 2))))
(interleave head (reverse tail))))
The above implementation IMHO is a bit more intuitive, and if you're working with Racket it doesn't require external libraries. It works as expected:
(zippy '(1 2 3 4 5 6))
=> '(1 6 2 5 3 4)

Scheme, sublist

The function is called sublist? with two arguments (both lists). It checks whether l2 is a sublist of l1 and returns #t or #f.
I have this so far, but seems the exists function is not working properly
(define (sublist? l1 l2)
(cond ((null? l2) #t)
((exists l1 (car l2)) #t)
(else (sublist? l1 (cdr l2)))))
(define (exists l p)
(if (null? l) #f
(or (equal? p (car l)) (exists (cdr l) p))))
updated
First of all I think in your exists function, you are missing an equals?
And it seems the first parameter is the one that's supposed to be an atom, but in your sublist function you send the list first and the atom next, you need to switch the parameters.
(define (exists l p)
(if (null? l) #f
(or (equal? p (car l)) (exists (cdr l) p))))
That should work fine.
Also, its convention to call your predicate functions as a question, you should name it exists?
[Edit]
Also upon closer inspection, it looks like your sublist? function is incorrect. It will return #t even if only one element of the sublist exists in the list. You need to modify it a bit into:
(define (sublist? l1 l2)
(cond ((null? l2) #t)
((not (exists l1 (car l2))) #f)
(else (sublist? l1 (cdr l2)))))
Now you are saying:
1) Is empty? Then is a sublist.
2) Is this element NOT in the list? Then is not.
3) If it is, then check the rest of the elements.
I believe the previous answer only checks subsets, not sublists. Order matters for sublists, so you can't simply check the existence of elements in the list. You need to do something like the following.
(define (sublist? l1 l2)
(cond ((null? l2) #t)
((null? l1) #f)
((headlist? l1 l2) #t)
(else (sublist? (cdr l1) l2)))
(define (headlist? l1 l2)
(cond ((null? l2) #t)
((null? l1) #f)
((not (equal? (car l1) (car l2))) #f)
(else headlist? (cdr l1) (cdr l2))))

Linearly recursive list-difference function in Common Lisp

I was going through this tutorial for fun, and got stuck on the very last thing he says, "Exercise: Give a linearly recursive implementation of union and difference." (for a list)
Union, no sweat.
Difference, sweat.
An attempt looks like this. . .
(defun list-diff (L1 L2)
(cond
((null L1) L2)
((null (member (first L1) L2)) (cons (first L1) (list-diff (rest L1) L2)))
(t (list-diff (rest L1) L2))
)
)
Now, that returns all the elements that are in L1 that aren't in L2, but it just returns all of L2 (obviously). Similarly, if I change the L2 in line 3 to "nil", then it just returns all of L1 that aren't in L2, but none of L2.
My attempts at work-arounds don't look recursive, and when they are, I end up getting stack-overflows (like if I try calling (list-diff L2 L1) somewhere).
Any of his other exercises, such as list-intersection, only require running through the elements of L1. Here, I want to strike the crucial elements from L2, or run (list-diff L2 L1) and then union the results from both, but that's not really linearly-recursive anymore.
Thoughts?
(not homework, really. I just thought I'd try to look at some LISP for fun.)
EDIT: a function that does this properly, based on the responses is:
(defun list-diff (L1 L2)
(cond
((null L1) nil)
((null (member (first L1) L2)) (cons (first L1) (list-diff (rest L1) L2)))
(t (list-diff (rest L1) L2))
)
)
The set difference operation L1 \ L2 is defined as all elements e such that e is in L1 but e not in L2. So it looks to me like your second attempt is actually correct:
Similarly, if I change the L2 in line
3 to "nil", then it just returns all
of L1 that aren't in L2, but none of
L2.
It looks like you're trying to compute the symmetric difference, although it isn't clear to me that this is what the exercise requests.
If you want to be clever about it, you can probably pass a third list into the function to serve as an accumulator. When L1 has elements, push the first element into the accumulator (and call recursively) when (null (member (first L1) L2)). When L1 is null, check the elements of L2 against the accumulator list, doing the same thing. When L1 and L2 are null, return the accumulator list.
In Lisp this is the definition of 'set difference':
set-difference list1 list2 &key (test #'eql) test-not (key #'identity)
Function
Returns a list of elements of list1 that do not appear in list2.
That's your modified implementation:
(defun list-diff (L1 L2)
(cond
((null L1) L1)
((member (first L1) L2) (list-diff (rest L1) L2))
(t (cons (first l1) (list-diff (rest l1) l2)))))

Resources