LISP common list function - lisp

Hey guys I have one last problem Im trying to solve for my semester. I need to create:
(myCommon L1 L2)
Evaluates to a list of elements that are common in both lists L1 and L2.
Assume L1 and L2 have no repeated elements.
eg. (myCommon ‘(p a e g) ‘(a q r e)) → (a e)
I can only use the following functions:
(atom X)
(quote X)
‘X
(eq X Y)
(cons X L)
(car L)
(cdr L)
(list A B C)
(if X Y Z) .
(cond (C1 S1) (C2 S2) …… (Cn Sn))
(lambda (P1 P2 …… Pn) E)
(funcall F (P1 P2 …… Pn))
I can also use the functions I have created within the assignment. So far I have created:
(defun myLast (L)
(if (eq (cdr L) '())
(car L)
(myLast (cdr L)))) ;Evaluates to the last element of list L
(defun myCount (X L)
(cond ((eq L '()) 0)
((eq X (car L))(+ 1 (myCount X (cdr L))))
(+ (myCount X (cdr L))))) ;Evaluates to number of occurrences of X in L
(defun myMember (X L)
(cond ((eq L '()) '())
((eq X (car L)) t)
(t (myMember X (cdr L))))) ;Evaluates to true if X in L, false otherwise
The problem with this assignment is I cant meet up with the teacher to ask questions as hes gone, and has "limited email access" right now. I cant ask questions on how to solve this problem and I am very confused on even where to start for this function. I think I would have to use myMember on like the car of L1 and check if its in L2, if it is put it in a new list and recursively add to the list. I wasnt sure how to do this. Could anyone help me out so I can finally finish this semester? Thank you!

Your idea is a good one. You should look at the pattern you used in myCount. You can use nearly the same pattern for myCommon.
Think about how to bottom out of the recursion. You are building up a list, not a number, so instead of 0 as the terminal value, think about what the end of a list is.
For the recursion clauses, instead of using + 1 when you should include the item, use a function that adds an item to a list.
Remember to only recurse down one of the lists in myCommon. You should be looking at one element at a time, and compare that element to the complete second list, which for the purposes of myCommon should be a constant.
Hopefully this should help you along, in the spirit of your previous functions. But this is a very inefficient way of implementing a intersection-function.
A common trick which can help your compiler produce more efficient code is to use a helper function with a third parameter - an accumulator that you build up as you recurse down one of your input lists. (The accumulator trick lets you write your function in a style called tail recusive.)
And when you are not doing artificially restricted excercises to learn recursion, I would prefer to use iteration (loop or dolist) to solve this, especially when you are using common lisp, which doesn't mandate that the compiler produces efficient code even for the tail recursive calls. But then again, if you're not using a restricted version of common lisp, you could just call the built-in function intersection. :-)

Related

Insertion Sort in Common lisp

I want to implement the sorting function in common-lisp with this INSERT function
k means cons cell with number & val, and li means list where I want insert k into.
with this function, I can make a list of cell
(defun INSERT (li k) (IF (eq li nil) (cons (cons(car k)(cdr k)) nil)
(IF (eq (cdr li) nil)
(IF (< (car k)(caar li)) (cons (cons(car k)(cdr k)) li)
(cons (car li) (cons (cons(car k)(cdr k)) (cdr li)) )
)
(cond
( (eq (< (caar li) (car k)) (< (car k) (caadr li)) )
(cons (car k) (cons (cons (car k) (cdr k)) (cdr li)) ) )
(t (cons (car li) (INSERT (cdr li) k)) )))))
and what I want is the code of this function below. it has only one parameter li(non sorted list)
(defun Sort_List (li)(...this part...))
without using assignment, and using the INSERT function
Your insert function is very strange. In fact I find it so hard to read that I cn't work out what it's doing except that there's no need to check for both the list being null and its cdr being null. It also conses a lot of things it doesn't need, unless you are required by some part of the specification of the problem to make copies of the conses you are inserting.
Here is a version of it which is much easier to read and which does not copy when it does not need to. Note that this takes its arguments in the other order to yours:
(defun insert (thing into)
(cond ((null into)
(list thing))
((< (car thing) (car (first into)))
(cons thing into))
(t (cons (first into)
(insert thing (rest into))))))
Now, what is the algorithm for insertion sort? Well, essentially it is:
loop over the list to be sorted:
for each element, insert it into the sorted list;
finally return the sorted list.
And we're not allowed to use assignment to do this.
Well, there is a standard trick to do this sort of thing, which is to use a tail-recursive function with an accumulator argument, which accumulates the results. We can either write this function as an explicit auxiliary function, or we can make it a local function. I'm going to do the latter both because there's no reason for a function which is only ever used locally to be globally visible, and because (as I'm assuming this is homework) it makes it harder to submit directly.
So here is this version of the function:
(defun insertion-sort (l)
(labels ((is-loop (tail sorted)
(if (null tail)
sorted
(is-loop (rest tail) (insert (first tail) sorted)))))
(is-loop l '())))
This approach is fairly natural in Scheme, but not very natural in CL. An alternative approach which does not use assignment, at least explicitly, is to use do. Here is a version which uses do:
(defun insertion-sort (l)
(do ((tail l (rest tail))
(sorted '() (insert (first tail) sorted)))
((null tail) sorted)))
There are two notes about this version.
First of all, although it's not explicitly using assignment it pretty clearly implicitly is doing so. I think that's probably cheating.
Secondly it's a bit subtle why it works: what, exactly, is the value of tail in (insert (first tail) sorted), and why?
A version which is clearer, but uses loop which you are probably not meant to know about, is
(defun insertion-sort (l)
(loop for e in l
for sorted = (insert e '()) then (insert e sorted)
finally (return sorted)))
This, however, is also pretty explicitly using assignment.
As Kaz has pointed out below, there is an obvious way (which I should have seen!) of doing this using the CL reduce function. What reduce does, conceptually, is to successively collapse a sequence of elements by calling a function which takes two arguments. So, for instance
(reduce #'+ '(1 2 3 4))
is the same as
(+ (+ (+ 1 2) 3) 4)
This is easier to see if you use cons as the function:
> > (reduce #'cons '(1 2 3 4))
(((1 . 2) . 3) . 4)
> (cons (cons (cons 1 2) 3) 4)
(((1 . 2) . 3) . 4)
Well, of course, insert, as defined above, is really suitable for this: it takes an ordered list and inserts a new pair into it, returning a new ordered list. There are two problems:
my insert takes its arguments in the wrong order (this is possibly why the original one took the arguments in the other order!);
there needs to be a way of 'seeding' the initial sorted list, which will be ().
Well we can fix the wrong-argument-order either by rewriting insert, or just by wrapping it in a function which swaps the arguments: I'll do the latter because I don't want to revisit what I wrote above and I don't want two versions of the function.
You can 'seed' the initial null value by either just prepending it to the list of things to sort, or in fact reduce has a special option to provide the initial value, so we'll use that.
So using reduce we get this version of insertion-sort:
(defun insertion-sort (l)
(reduce (lambda (a e)
(insert e a))
l :initial-value '()))
And we can test this:
> (insertion-sort '((1 . a) (-100 . 2) (64.2 . "x") (-2 . y)))
((-100 . 2) (-2 . y) (1 . a) (64.2 . "x"))
and it works fine.
So the final question the is: are we yet again cheating by using some function whose definition obviously must involve assignment? Well, no, we're not, because you can quite easily write a simplified reduce and see that it does not need to use assignment. This version is much simpler than CL's reduce, and in particular it explicitly requires the initial-value argument:
(defun reduce/simple (f list accum)
(if (null list)
accum
(reduce/simple f (rest list) (funcall f accum (first list)))))
(Again, this is not very natural CL code since it relies on tail-call elimination to handle large lists, but it makes the point that you can do this without assignment.)
And so now we can write one final version of insertion-sort:
(defun insertion-sort (l)
(reduce/simple (lambda (a e)
(insert e a))
l '()))
And it's easy to check that this works as well.

Delete all Occurrences

Delete all occurrences Problem 5 (0 / 32)
Define a function deleteAll that has two input argument x and L, where x is an atom and L is a list that contains atomic elements and sublists to any level, and the function returns a list where all occurrences of x are deleted from the list L.
I have problem when list has sublists. I cant go recursively in sublists to check whether it has contains duplicate or not.
(defun deleteAll (x L)
(cond
((null L) nil)
((not(atom(car L))) (deleteAll x (cdr L)))
((not(eq x (car L))) (cons (car L) (deleteAll x (cdr L ))))
(T(deleteAll x (cdr L)))))
In the second term you know from the predicate that you got a list in the first element. You should do the same as the third consequent except you need to process the car as well as the cdr.

I don't know what this function should do

I have here a function that I need to modify so that I would avoid the double recursive call of (f (car l)) . First of all I can't figure it out what it shows..
If I pass (f '((3 4) 5 6)) it shows me CAR: 3 is not a list
Can anybody help me understand and then modify it?
(DEFUN F (L)
(COND
((NULL L) 0)
((> (f (car l)) 2) (+ (car l) (f (cdr l))))
(T (f (CAR L)))
))
You can figure out what this function should accept as input by looking at what it does with the input, and what it returns by looking at what each case returns. There are three cases:
Case 1
((NULL L) 0)
In this case, L can be nil, and 0, which is a number, is returned.
Case 2
((> (f (car l)) 2) (+ (car l) (f (cdr l))))
In this case, we call both car and cdr on l, so l had better be a cons. We also compare (f (car l)) with 2, so f must return a number, at least for whatever type (car l) is. Since we're calling + with (car l), (car l) must be a number. So f must return a number when given a number. Now, we're also calling + with (f (cdr l)), so whatever type (cdr l) has, f had better return a number for it, too.
Case 3
(T (f (CAR L)))
This doesn't put many constraints on us. This just says that if we didn't have either of the first two cases, then we return (f (car l)). Since checking the second case didn't fail, and because we're calling (car l), l still has to be a cons in this case.
So what is f?
Well, it's still not immediately clear what f is, but we can write it as a piecewise function, and maybe that will help. It take a list, which is either the empty list or a cons that has a first and a rest.
f [] = 0
f x:xs = if (f x) > 2
then x + (f xs)
else (f x)
To modify it so that you only call (f (car l)) is easy enough, although since we know that the input needs to be a list, I'm going to use first and rest to suggest that, rather than car and cdr.
(defun f (list)
(if (endp list)
0
(let ((tmp (f (first list))))
(if (> tmp 2)
(+ (first list)
(f (rest list)))
tmp))))
Let's try to walk through some possible inputs and try to cover the different code branches. What sort of input could we call this with? Well, we can call it with ():
CL-USER> (f '())
0
That takes care of the first then branch. Now what if we want to hit the second? Then we need to pass something that's not the empty list, so it looks like (? . ??). Now the first thing that has to happen is a recursive call to(f (first list)). The only way that this is going to work is if(first list)is also a list that we can pass tofand get a value back. Then(first list)` must have either been the empty list or another suitable list. So we can call:
CL-USER> (f '(() a b c))
0
In general, we can call f with () and with any list such that (first (first (first ... (first list)))) is (). Can we call it with anything else? It doesn't appear so. So now we know what the acceptable inputs to f are:
input ::= ()
| (input . anything)
and the output will always be 0.

LISP - count occurences of every value in a list

I apologize for the bad English..
I have a task to write a function called "make-bag" that counts occurences of every value in a list
and returns a list of dotted pairs like this: '((value1 . num-occurences1) (value2 . num-occurences2) ...)
For example:
(make-bag '(d c a b b c a))
((d . 1) (c . 2) (a . 2) (b . 2))
(the list doesn't have to be sorted)
Our lecturer allows us to us functions MAPCAR and also FILTER (suppose it is implemented),
but we are not allowed to use REMOVE-DUPLICATES and COUNT-IF.
He also demands that we will use recursion.
Is there a way to count every value only once without removing duplicates?
And if there is a way, can it be done by recursion?
First of, I agree with Mr. Joswig - Stackoverflow isn't a place to ask for answers to homework. But, I will answer your question in a way that you may not be able to use it directly without some extra digging and being able to understand how hash-tables and lexical closures work. Which in it's turn will be a good exercise for your advancement.
Is there a way to count every value only once without removing duplicates? And if there is a way, can it be done by recursion?
Yes, it's straight forward with hash-tables, here are two examples:
;; no state stored
(defun make-bag (lst)
(let ((hs (make-hash-table)))
(labels ((%make-bag (lst)
(if lst
(multiple-value-bind (val exists)
(gethash (car lst) hs)
(if exists
(setf (gethash (car lst) hs) (1+ val))
(setf (gethash (car lst) hs) 1))
(%make-bag (cdr lst)))
hs)))
(%make-bag lst))))
Now, if you try evaluate this form twice, you will get the same answer each time:
(gethash 'a (make-bag '(a a a a b b b c c b a 1 2 2 1 3 3 4 5 55)))
> 5
> T
(gethash 'a (make-bag '(a a a a b b b c c b a 1 2 2 1 3 3 4 5 55)))
> 5
> T
And this is a second example:
;; state is stored....
(let ((hs (make-hash-table)))
(defun make-bag (lst)
(if lst
(multiple-value-bind (val exists)
(gethash (car lst) hs)
(if exists
(setf (gethash (car lst) hs) (1+ val))
(setf (gethash (car lst) hs) 1))
(make-bag (cdr lst)))
hs)))
Now, if you try to evaluate this form twice, you will get answer doubled the second time:
(gethash 'x (make-bag '(x x x y y x z z z z x)))
> 5
> T
(gethash 'x (make-bag '(x x x y y x z z z z x)))
> 10
> T
Why did the answer doubled?
How to convert contents of a hash table to an assoc list?
Also note that recursive functions usually "eat" lists, and sometimes have an accumulator that accumulates the results of each step, which is returned at the end. Without hash-tables and ability of using remove-duplicates/count-if, logic gets a bit convoluted since you are forced to use basic functions.
Well, here's the answer, but to make it a little bit more useful as a learning exercise, I'm going to leave some blanks, you'll have to fill.
Also note that using a hash table for this task would be more advantageous because the access time to an element stored in a hash table is fixed (and usually very small), while the access time to an element stored in a list has linear complexity, so would grow with longer lists.
(defun make-bag (list)
(let (result)
(labels ((%make-bag (list)
(when list
(let ((key (assoc (car <??>) <??>)))
(if key (incf (cdr key))
(setq <??>
(cons (cons (car <??>) 1) <??>)))
(%make-bag (cdr <??>))))))
(%make-bag list))
result))
There may be variations of this function, but they would be roughly based on the same principle.

Lisp list iteration

I have a function that gets x(a value) and xs(a list) and removes all values that are bigger than x from the list. Well it doesn't work, can you tell me why?
(defun biggerElems(x xs)
(let ((xst))
(dolist (elem xs)
(if (> x elem)
(setf xst (remove elem xs))))
xst))
I think it's this line that's not right:
(setf xst (remove elem xs))))
The first argument to setf is the place, followed by the value. It looks like you have it backwards (and xst is either nil or uninitialized).
You might find it easier to do this:
(defun biggerElems (x xs)
(remove-if (lambda (item) (> item x)) xs))
Most concise AFAIK:
(defun bigger-elements (x xs) (remove x xs :test #'<))
returning a fresh list, it removes all elements y from xs for which
(< y x)
or using the famous LOOP:
(defun bigger-elements-2 (x xs)
(loop for e in xs
unless (< e x)
collect e))
It worked like that:
(defun filterBig (x xs)
(remove-if (lambda (item) (> item x)) xs))
What was the '#' for? It didn't compile with it.
If you want to do this the Lisp Way, you could use recursion to return the new list:
(defun biggerElems (x xs)
(cond ((null xs) NIL)
((< x (car xs))
(biggerElems x (cdr xs)))
(t
(cons (car xs) (biggerElems x (cdr xs))))))
#Luís Oliveira
This solution is to contrast with the one posted in the question. Had we needed to do something slightly more complicated it's important to be grounded in the recursive approach to manipulating lists.
#Ben: It isn't the setf call that is wrong--the problem is that he is not updating xs.
ie: xst is being set to xs with the element removed, but xs is not being updated. If a second element is to be removed, xst will have the first back in it.
you would need to bind xst to xs, and replace the xs in the remove call with xst. This would then remove all elements x is bigger than. ie:
(defun biggerElems(x xs)
(let ((xst xs))
(dolist (elem xs)
(when (> x elem)
(setf xst (remove elem xst))))
xst))
It might be slightly faster to set xst to (copy-list xs) and then use delete instead of remove (delete is destructive... depending on your implementation, it may be faster than remove. Since you are calling this multiple times, you may get better performance copying the list once and destructively deleting from it).
Alternatively:
(defun bigger-elems (x xs) ; I prefer hyphen separated to camelCase... to each his own
(loop for elem in xs when (<= x elem) collect elem))
Looking back over your original post, it is a little confusing... you say you remove all elements bigger than x, but your code looks like it is attempting to remove all elements x is bigger than. The solutions I wrote return all elements bigger than x (ie: remove all elements x is bigger than).
What was the '#' for? It didn't
compile with it.
Typo. Normally you refer to functions with #' (like (remove-if #'oddp list)), but when I was editing, I forgot to remove the '#'.