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.
Related
I've got a homework assignment that has stumped me! I have to create a function goo(A L) that will remove every A in L and it has to work on nested lists also.
Here's what I've got so far
(defun goo(A L)
(cond ((null L) nil) ; if list is null, return nil
(T ; else list is not null
(cond ((atom (car L))) ;if car L is an atom
((cond ((equal A (car L)) (goo A (cdr L))) ;if car L = A, call goo A cdr L
(T (cons (car L) (goo A (cdr L)))))) ;if car L != A,
(T (cons (goo A (car L)) (goo A (cdr L)))))) ;else car L is not atom, call goo on car L and call goo on cdr L
))
This function returns True no matter what I give it.
You parens are messed up. Move the last paren around (atom (car L)) to include the next cond expression. I suggest using an IDE which shows matching parens.
As for styling, if you didn't know, cond can accept multiple clauses. This way you don't need to have the t and then the cond again. You can also use 'if' if you are only testing a single predicate and making a decision based solely on that.
Note: this was originally posted as an edit to the question by the original asker in revision 2.
I tried another approach and it's working now.
(defun goo(A L)
(cond ((null L) nil)
((atom (car L)) (cond ((equal A (car L)) (goo A (cdr L)))
(T (cons (car L) (goo A (cdr L))))))
(T (cons (goo A (car L)) (goo A (cdr L))))
))
Note 2: this should conventionally be formatted like this to show the program structure:
(defun goo (a l)
(cond ((null l) nil)
((atom (car l))
(cond ((equal a (car l))
(goo a (cdr l)))
(t (cons (car l)
(goo a (cdr l))))))
(t (cons (goo a (car l))
(goo a (cdr l))))))
I think it might be easier to look at this a replacement into trees problem. It's easy to define a function that takes a tree and replaces subtrees in it that satisfy a test. There's a standard function subst-if that does that, but it replaces every matching subtree with the same thing. It will be more useful to us if we replace the element with a value computed from the subtree:
(defun %subst-if (new test tree)
"Replace subtrees of TREE that satisfy TEST with the result
of calling NEW with the subtree."
(cond
;; If tree satifies the test, return (new tree).
((funcall test tree)
(funcall new tree))
;; If tree is a cons, recurse.
((consp tree)
(cons (%subst-if new test (car tree))
(%subst-if new test (cdr tree))))
;; Otherwise, just return the leaf.
(tree)))
With this, its easy to define the kind of function we need. When an element X appears somewhere in a nested list structure, it means that there is a cons cell whose car is X. We want to replace that cons cell with its cdr, but to also recurse on the cdr of the cell. This isn't hard:
(defun replace* (x list &key (test 'eql))
"Remove occurrences of X in LIST and its sublists."
(%subst-if
(lambda (cons)
"Replace elements of the form (X . more) with
(replace* x more :test test)."
(replace* x (cdr cons) :test test))
(lambda (subtree)
"Detect subtrees of the form (X . more)."
(and (consp subtree)
(funcall test x (car subtree))))
list))
(replace* 'a '(1 a (2 a 3) a 4 a 5))
;=> (1 (2 3) 4 5)
I've got a homework assignment that has stumped me! I have to create a function goo(A L) that will remove every A in L and it has to work on nested lists also.
Here's what I've got so far
(defun goo(A L)
(cond ((null L) nil) ; if list is null, return nil
(T ; else list is not null
(cond ((atom (car L))) ;if car L is an atom
((cond ((equal A (car L)) (goo A (cdr L))) ;if car L = A, call goo A cdr L
(T (cons (car L) (goo A (cdr L)))))) ;if car L != A,
(T (cons (goo A (car L)) (goo A (cdr L)))))) ;else car L is not atom, call goo on car L and call goo on cdr L
))
This function returns True no matter what I give it.
You parens are messed up. Move the last paren around (atom (car L)) to include the next cond expression. I suggest using an IDE which shows matching parens.
As for styling, if you didn't know, cond can accept multiple clauses. This way you don't need to have the t and then the cond again. You can also use 'if' if you are only testing a single predicate and making a decision based solely on that.
Note: this was originally posted as an edit to the question by the original asker in revision 2.
I tried another approach and it's working now.
(defun goo(A L)
(cond ((null L) nil)
((atom (car L)) (cond ((equal A (car L)) (goo A (cdr L)))
(T (cons (car L) (goo A (cdr L))))))
(T (cons (goo A (car L)) (goo A (cdr L))))
))
Note 2: this should conventionally be formatted like this to show the program structure:
(defun goo (a l)
(cond ((null l) nil)
((atom (car l))
(cond ((equal a (car l))
(goo a (cdr l)))
(t (cons (car l)
(goo a (cdr l))))))
(t (cons (goo a (car l))
(goo a (cdr l))))))
I think it might be easier to look at this a replacement into trees problem. It's easy to define a function that takes a tree and replaces subtrees in it that satisfy a test. There's a standard function subst-if that does that, but it replaces every matching subtree with the same thing. It will be more useful to us if we replace the element with a value computed from the subtree:
(defun %subst-if (new test tree)
"Replace subtrees of TREE that satisfy TEST with the result
of calling NEW with the subtree."
(cond
;; If tree satifies the test, return (new tree).
((funcall test tree)
(funcall new tree))
;; If tree is a cons, recurse.
((consp tree)
(cons (%subst-if new test (car tree))
(%subst-if new test (cdr tree))))
;; Otherwise, just return the leaf.
(tree)))
With this, its easy to define the kind of function we need. When an element X appears somewhere in a nested list structure, it means that there is a cons cell whose car is X. We want to replace that cons cell with its cdr, but to also recurse on the cdr of the cell. This isn't hard:
(defun replace* (x list &key (test 'eql))
"Remove occurrences of X in LIST and its sublists."
(%subst-if
(lambda (cons)
"Replace elements of the form (X . more) with
(replace* x more :test test)."
(replace* x (cdr cons) :test test))
(lambda (subtree)
"Detect subtrees of the form (X . more)."
(and (consp subtree)
(funcall test x (car subtree))))
list))
(replace* 'a '(1 a (2 a 3) a 4 a 5))
;=> (1 (2 3) 4 5)
(pred 'r '(p q r)) -> q
Here's my idea-
- I have tried finding the function that returns the length of a specific element, but due to my lack of syntactical knowledge, I am unable to use the function.
- By using the length function as my helper function, I am trying to find the predecessor of an element in the list.
I hope that gives you guys some idea to start with or if you guys have a better idea, please let me know and also please show the coding too..
Thank you!
Based on your current attempt, here's a corrected version (with corrected indentation, as a bonus :-)):
(defun pred (x l)
(cond ((null (cdr l)) (car l))
((eq (cadr l) x) (car l))
(t (pred x (cdr l)))))
Are you sure you want to return the last element of the list if your expected element isn't found? It seems...strange, I'd have thought nil is a better return value.
Update: the OP wanted to implement both successor and predecessor functions. Here's how I'd implement them, in Scheme. (Sorry, not doing your homework for you, but if you know how to translate Scheme into Common Lisp, your life would be easier.)
(define (succ x lst)
(cond ((memv x lst) => (lambda (mem)
(and (pair? (cdr mem))
(cadr mem))))
(else #f)))
(define (pred x lst)
(let loop ((prev #f)
(rest lst))
(cond ((null? rest) #f)
((eqv? (car rest) x) prev)
(else (loop (car rest) (cdr rest))))))
and while memv is built-in to Scheme, you could implement it yourself quite simply:
(define (memv x lst)
(let loop ((rest lst))
(cond ((null? rest) #f)
((eqv? (car rest) x) rest)
(else (loop (cdr rest))))))
In particular, note the similarity between memv and pred.
You don't particularly need a length function to do this.
The obvious classical approach would be that if the cadr of the list equals the element you want, return the car of the list. Otherwise, return the search function on the cdr of the list. Other than that, you just need to deal with the boundary conditions (e.g., list that's empty or contains only one item).
I have no problem combining the lists but sorting them in ascending order is where i am struggling.
(define (combineASC l1 l2)
(cond
((null? l1) l2)
(#t (cons (car l1) (combineASC (cdr l1) l2)))
(sort l2 #'<))) ; I found this part in an online source
This is the output i get:
(combineASC '(2 4 6) '(1 4 5))
(2 4 6 1 4 5)
Does anyone have any suggestions for me?
So you're combining two input lists, each already sorted in ascending order. You want to "weave" them into one, also in ascending order.
For that, you just take both head elements (each from each input list) and compare; then you take the smallest out from its list, and combine further what you're left with - using same function.
There will be no sorting involved. The resulting list will be already sorted, by virtues of the process that defines it.
This operation is commonly called "merge". It preserves duplicates. Its duplicates-removing counterpart, merging two ordered lists into one as well, is known a "union". That is because these ordered (non-descending, or strictly ascending) lists can be seen as representation of sets.
Another subtlety to take note of is, what to do when the two head elements are equal. We've already decided to preserve the duplicates, yes, but which of the two to take out first?
Normally, it's the left one. Then when such defined merge operation is used as part of merge sort, the sort will be stable (of course the partitioning has to be defined properly for that too). Stable means, the original order of elements is preserved.
For example, if the sort is stable, when sorting by the first element of pairs, (3,1) (1,2) (3,3) is guaranteed to be sorted as (1,2) (3,1) (3,3) and not as (1,2) (3,3) (3,1).
So, following the skeleton of your code, we get
;; combine two non-decreasing lists into one non-decreasing list,
;; preserving the duplicates
(define (combineNONDECR l1 l2)
(cond
((null? l1) l2)
((null? l2) l1)
((<= (car l1) (car l2))
(cons (car l1) (combineNONDECR (cdr l1) l2)))
(t
(cons (car l2) (combineNONDECR l1 (cdr l2))))))
But if you really need the result to be in ascending order, as opposed to non-decreasing, then you'd have to tweak this a little bit - make the = case separate, and handle it separately, to stop the duplicates from creeping in (there are no duplicates in each of the ascending-order lists, but the lists might contain some duplicates between the two of them).
Because tail recursive :)
(define (merge-sorted . lists)
(define (%merge-sorted head tails)
(cond
((null? tails) head)
((null? (car tails))
(%merge-sorted head (cdr tails)))
(else (let ((sorted
(sort tails
(lambda (a b)
(<= (car a) (car b))))))
(%merge-sorted (cons (caar sorted) head)
(cons (cdar sorted) (cdr sorted)))))))
(reverse (%merge-sorted '() lists)))
(merge-sorted '(1 2 3) '(4 5 6 7 8 9) '(2 4 6) '(1 3 5 7))
it scales better :P
I think this is what Will was talking about:
(define (merge-sorted . lists)
(define (%swap-if-greater lists)
(define (%do-swap head next built tails)
(cond
((null? tails)
(append (reverse built)
(cond
((null? next) (list head))
((> (car head) (car next))
(list next head))
(else (list head next)))))
((> (car head) (car next))
(%do-swap head (car tails)
(cons next built) (cdr tails)))
(else (append (reverse built)
(list head) (list next) tails))))
(%do-swap (car lists)
(if (null? (cdr lists)) '() (cadr lists))
'() (if (null? (cdr lists)) '() (cddr lists))))
(define (%merge-sorted head tails)
(cond
((null? tails) head)
((null? (car tails))
(%merge-sorted head (cdr tails)))
(else (let ((sorted (%swap-if-greater tails)))
(%merge-sorted (cons (caar sorted) head)
(cons (cdar sorted)
(cdr sorted)))))))
(reverse
(%merge-sorted
'() (sort lists (lambda (a b) (<= (car a) (car b)))))))
Especially given Schemes... interesting position on booleans, I wouldn't be very enthusiastic about this one.
(defun merge (l1 l2)
(if (not (and (eql nil l1) (eql l2 nil))
(if (> (car l1) (car l2))
(cons (car l1) (merge (cdr l1) l2))
(cons (car l2) (merge (cdr l2) l1)))
;;;append the not-nil string to the rest.
)
that should work (you still need to complete the code, but the idea is clear)
note this code is in common-lisp.
look up merge sort for more info about the technique
I need to remove an element from a list which contain inner lists inside. The predefined element should be removed from every inner list too.
I have started working with the following code:
(SETQ L2 '(a b ( a 2 b) c 1 2 (D b (a s 4 2) c 1 2 a) a )) ; defined my list
; Created a function for element removing
(defun elimina (x l &optional l0)
(cond (( null l)(reverse l0))
((eq x (car l))(elimina x (cdr l) l0))
(T (elimina x (cdr l) (cons (car l) l0))))
)
(ELIMINA 'a L2)
But unfortunately it removes only elements outside the nested lists.
I have tried to create an additional function which will remove the element from the inner lists.
(defun elimina-all (x l)
(cond ((LISTP (CAR L))(reverse l)(elimina x (car l)))
(T (elimina-all x (CDR L)))
)
)
but still unsuccessfully.
Can you please help me to work it out?
Thank you in advance.
First of all, I'd suggest you read this book, at least, this page, it explains (and also gives very good examples!) of how to traverse a tree, but most importantly, of how to combine functions to leverage more complex tasks from more simple tasks.
;; Note that this function is very similar to the built-in
;; `remove-if' function. Normally, you won't write this yourself
(defun remove-if-tree (tree predicate)
(cond
((null tree) nil)
((funcall predicate (car tree))
(remove-if-tree (cdr tree) predicate))
((listp (car tree))
(cons (remove-if-tree (car tree) predicate)
(remove-if-tree (cdr tree) predicate)))
(t (cons (car tree)
(remove-if-tree (cdr tree) predicate)))))
;; Note that the case of the symbol names doesn't matter
;; with the default settings of the reader table. I.e. `D' and `d'
;; are the same symbol, both uppercase.
;; Either use \ (backslash) or || (pipes
;; around the symbol name to preserve the case. Eg. \d is the
;; lowercase `d'. Similarly, |d| is a lowercase `d'.
(format t "result: ~s~&"
(remove-if-tree
'(a b (a 2 b) c 1 2 (D b (a s 4 2) c 1 2 a) a)
#'(lambda (x) (or (equal 1 x) (equal x 'a)))))
Here's a short example of one way to approaching the problem. Read the comments.
Maybe like this:
(defun elimina (x l &optional l0)
(cond ((null l) (reverse l0))
((eq x (car l)) (elimina x (cdr l) l0))
(T (elimina x (cdr l) (cons (if (not (atom (car l)))
(elimina x (car l))
(car l))
l0)))))
I was looking for the same answer as you and, unfortunately, I couldn't completely understand the answers above so I just worked on it and finally I got a really simple function in Lisp that does exactly what you want.
(defun remove (a l)
(cond
((null l) ())
((listp (car l))(cons (remove a (car l))(remove a (cdr l))))
((eq (car l) a) (remove a (cdr l)))
(t (cons (car l) (remove a (cdr l))))
)
)
The function begins with two simple cases, which are: 'list is null' and 'first element is a list'. Following this you will "magically" get the car of the list and the cdr of the list without the given element. To fixed that up to be the answer for the whole list you just have to put them together using cons.