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.
Related
I'm trying to display one value from the list by the function is displaying the entire list instead of one value. Code below using elisp.
(defun element-i (L number)
(if (not L) nil
(if (< (length L) number) nil
(dotimes (i number L)
(pop L)))))
You're returning L from dotimes, which is the remaining list after popping number elements from it.
If you want to get just the element, you should return the first element of L using car.
(defun element-i (L number)
(cond ((null L) nil)
((< (length L) number) nil)
(t (dotimes (i number (car L))
(pop L)))))
I also recommend using cond when you have multiple conditions to test, rather than nested if. And use the null predicate when testing a list; not should be used for logical contexts.
I am trying to do a function that removes duplicates from a list using Common Lisp on LispWorks.
So I did two functions. The first one "remove-e" removes an element from a list and a second one "remove-rep" uses the first one to return a list without duplicates.
Here is my code for the first one:
(defun remove-e (L e)
(if (null L)
L
(if (= e (car L))
(remove-e (cdr L) e)
(cons (car L) (remove-e (cdr L) e)))))
It works good when given a list of numbers but when I give it letters, I get this error:
(remove-e '(a a b a d a g a h t) a)
Error: The variable A is unbound.
For my second function:
(defun remove-rep (l)
(if (null l)
l
(cons (car l)
(remove-rep (remove-e (cdr l) (car l))))))
This is the error message that I get when trying to test it:
CL-USER 12 : 6 > (remove-rep '(1 2 3 1 5 1 1))
Error: The variable is unbound.
I saw that there are some similar questions, but couldn't find the common points of my program with these:
Unbound variable in Lisp ,
Unbound variable in Common Lisp
remove-e only works with a list of numbers, because you're using = to compare elements. If you want to be able to work with symbols as well, use eql:
(defun remove-e (L e)
(if (null L) L
(if (eql e (car L)) (remove-e (cdr L) e)
(cons (car L) (remove-e (cdr L) e)))))
Then when you call it, you have to quote the symbol argument, to prevent it from being evaluated as a variable.
(remove-e '(a a b a d a g a h t) 'a)
The problem in remove-rep is that you somehow typed some non-printing, multi-byte characters at the end of the first line. It works correctly with those characters removed. Try retyping the function, or just copy/paste this:
(defun remove-rep (l)
(if (null l) l
(cons (car l) (remove-rep (remove-e (cdr l) (car l))))))
BTW, Lisp programmers don't generally put ) on new lines like you do, they put them at the end of the line like this.
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. :-)
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.
I'm writing mergesort in Scheme and I'm curious as to why this won't work...
Here is the implementation I expect to work, but doesn't:
(define (mergesort op l)
(cond ((null? l) l)
((null? (cdr l)) l)
(else (merge op (car l)
(mergesort op (cdr l))))
)
)
And here is the 'proper' implementation.
(define (mergesort op l)
(cond ((null? l) l)
((null? (cdr l)) l)
(else (merge op (cons (car l) (list))
(mergesort op (cdr l))))
)
)
Why must I (cons (car l) (list)) before trying to merge it with the recursion?
Notice that this:
(cons (car l) (list))
... Is equivalent to this:
(list (car l))
In other words, you must pass a list with a single element and not just an element as the second parameter for the merge procedure.
Oscar is exactly correct, but there's one thing about this that has been overlooked.
This isn't mergesort. What's the definition of mergesort? It takes the list, splits it in half, sorts each sorted list, then merges them together.
You're not splitting in half; you're splitting into one and the rest. Then you sort the rest, and merge the single element into the list. But you can think of merging a single element into a list as inserting the element into a list.
Aha, there's a clue! You've written insertion sort. Which is fine; it works. It's just much less efficient.
So the difference between mergesort and insertion sort is picking the wrong place to split your list.