Difficulty writing LISP Recursive Function for Merge Sort - lisp

Hi so I have question that I am having some difficulty solving see below
Use the function SPLIT-LIST and MERGE-LISTS to define a recursive
Lisp function MSORT such that if L is a list of real numbers then (MSORT L) is a list consisting of the elements of L in ascending order. In the definition of MSORT you may call SPLIT-LIST,
MSORT itself, MERGE-LISTS, CAR, CDR, CADR and ENDP, but you should not call any
other function. Be sure to use LET or LET*, so that MSORT only calls SPLIT-LIST once.
So far I was able to write the SPLIT-LIST and MERGE-LISTS functions correctly but for M-SORT I am having difficulty writing the function. See below all three definitions so far. Any help on how to write the MSORT function correctly by following the guidelines in the question would be appreciated.
(defun SPLIT-LIST (L)
(if (endp L)
'(nil nil)
(let ((X (split-list (cdr L))))
(list (cons (car L)(cadr X)) (car X) ))))
(defun MERGE-LISTS (L1 L2)
(cond
((and(endp L1 )(endp L2)) nil )
((endp L1) (cons (CAR L2) (MERGE-LISTS nil (CDR L2))))
((endp L2) (cons (CAR L1) (MERGE-LISTS (CDR L1) NIL)))
((< (CAR L1) (CAR L2)) (cons (CAR L1) (MERGE-LISTS (CDR L1) L2 )))
((>= (CAR L1) (CAR L2)) (cons (CAR L2) (MERGE-LISTS L1 (CDR L2)) ))))
(defun MSORT (L)
(cond ((endp L ) nil)
( (equal (Length L) 1) L)
(T
(let* (
(S (SPLIT-LIST L ))
(L1 (CAR S))
(L2 (CADR S))
(X (MSORT (cdr L1)))
(Y (MSORT (cdr L2)))
)
(MERGE-LISTS
(if (and (numberp (car L1)) (numberp (car X))(<= (car L1 ) (car X)))
(list (car L1) (car X))
(list (car X) (car L1) )
)
(Cons (car L2) Y))
)))
)

You're overcomplicating it. You don't need to sort the CDRs of the sub-lists returned by SPLIT-LIST, just sort the whole lists, and merge them.
(defun MSORT (L)
(cond ((endp L) nil)
((endp (cdr L)) L)
(t
(let* ((S (SPLIT-LIST L ))
(L1 (car S))
(L2 (cadr S))
(X (MSORT L1))
(Y (MSORT L2)))
(MERGE-LISTS X Y)))))

Related

AutoLISP: Removing consecutive duplicates in list

I've been looking for an efficient way of removing consecutive duplicates in a list of points.
My original thinking was to loop through the elements of the list making a comparison with the (n-1)th element and removing it if its equal. But then it is not trivial to remove an element in a list and using another function would make it inefficient.
I am aware of Lee Mac's RemoveOnce function but I don't know how to modify it to make a comparison between consecutive elements of a list.
The goal as an example would be the following:
List = (p1 p2 p3 p3 p3 p2 p2 p4)
List_without_consecutive_duplicates = (p1 p2 p3 p2 p4)
Thanks!
Here's an iterative method:
(defun remcondupes ( l / r )
(while l
(if (not (equal (car l) (cadr l) 1e-8))
(setq r (cons (car l) r))
)
(setq l (cdr l))
)
(reverse r)
)
And here's a recursive method:
(defun remcondupes ( l )
(if l
(if (equal (car l) (cadr l) 1e-8)
(remcondupes (cdr l))
(cons (car l) (remcondupes (cdr l)))
)
)
)
In both of the above, the first element in the list is compared to the second using the equal function with a tolerance of 1e-8 (since we're comparing points), with the first element discarded if this test is validated.
Testing:
_$ (setq p1 '(1.2 2.3) p2 '(3.4 4.5) p3 '(5.6 6.7) p4 '(7.8 8.9))
(7.8 8.9)
_$ (setq lst (list p1 p2 p3 p3 p3 p2 p2 p4))
((1.2 2.3) (3.4 4.5) (5.6 6.7) (5.6 6.7) (5.6 6.7) (3.4 4.5) (3.4 4.5) (7.8 8.9))
_$ (remcondupes lst)
((1.2 2.3) (3.4 4.5) (5.6 6.7) (3.4 4.5) (7.8 8.9))
EDIT:
Alternatively, to account for consecutive points each successively within the comparison tolerance (per Will's comments below), you might consider the following variations:
(defun remcondupes ( l / r )
(while l
(if (equal (car l) (cadr l) 1e-8)
(setq l (cons (car l) (cddr l)))
(setq r (cons (car l) r)
l (cdr l)
)
)
)
(reverse r)
)
(defun remcondupes ( l )
(if l
(if (equal (car l) (cadr l) 1e-8)
(remcondupes (cons (car l) (cddr l)))
(cons (car l) (remcondupes (cdr l)))
)
)
)
Here is one way which I think is legal AutoLISP:
(defun remove-successive-duplicates (l / results current)
(cond
((null l)
l)
(t
(setq current (car l)
results (list current))
(foreach e (cdr l)
(cond
((not (eq e current))
(setq current e
results (cons e results)))))
(reverse results))))
You can do better than this if there are destructive functions on lists which it looks like there are not, or if there are list filtering functions which it also looks like there are not.
Here is another way which is much prettier but will cause stack overflows with long lists:
(defun remove-successive-duplicates (l)
(cond
((or (null l) (null (cdr l)))
l)
(t
(cons (car l) (remove-current-duplicates-loop (cdr l) (car l))))))
(defun remove-successive-duplicates-loop (l current)
(cond
((null (cdr l))
(cond
((eq (car l) current)
'())
(t
l)))
((eq (car l) current)
(remove-successive-duplicates-loop (cdr l) current))
(t
(cons (car l) (remove-successive-duplicates-loop (cdr l) (car l))))))

Lisp: Prevent double invocation of recursive function

How could I prevent the the double recursive call to (f (car l)) without using set/setq/setf ?
(defun f(l)
(cond
((null l) nil)
((listp (car l)) (append (f (car l)) (f (cdr l)) (car (f (car l)))))
(T (list (car l)))
)
)
You think the following solves it?
(defun f(l)
(cond
((null l) nil)
((listp (car l))
(funcall #'(lambda(ff) (append ff (f (cdr l)) (list (car ff)))) (f (car l))))
(T (list (car l)))
)
)
Your attempt is okay, but is usually written as:
...
(bar (foo abcde))
...
(baz (foo abcde))
...
->
(let ((r (foo abcde)))
...
(bar r)
...
(baz r)
...)
also note:
(funcall #'(lambda (foo) ...) bar)
can be written in Common Lisp as:
((lambda (foo) ...) bar)
or preferred, as already mentioned, as:
(let ((foo bar))
...)

multiplicating 2 vectors in lisp

I'm trying to multiplicate two vectors in lisp.
My code is:
(defun produs(x y)
(cond
((or (null x) (null y))
nil)
((eq (cdr x) nil)
(cons (* (car x) (car y))
(cdr y)))
((eq (cdr y) nil)
(cons (* (car x) (car y))
(cdr x)))
(t
(cons (* (car x) (car y))
(produs (cdr x) (cdr y))))))
When I verify
(produs '(7) '(1 2))
it gives me (7 2).
The 4rd line of code doesn't specify that if the rest of the body of x is nil, then to multiplicate it with all elements of y?
If I correctly understand what you want to achieve this code should work:
(defun produs(x y)
(cond
((or (null x) (null y)) nil)
((eq (cdr x) nil) ( cons (* (car x)(car y))(produs (cdr y) x )))
((eq (cdr y) nil) ( cons (* (car x)(car y)) (produs (cdr x) y)))
(t (cons (*(car x)(car y)) (produs (cdr x)(cdr y))))
)
)
The problem was that you were not "saying" to multiplicate all elements with the head x, but just adding all remaining elements in y to your result list.
(produs '(7) '(1 2)) => (7 14)
You could also try to refactor the code a little to avoid repeating yourself:
(defun produs (x y)
(when (and x y)
(cons (* (first x) (first y))
(let ((rx (rest x))
(ry (rest y)))
(cond
((and rx ry) (produs rx ry))
(rx (produs rx y))
(ry (produs ry x)))))))

EVAL/APPLY: too many arguments given to F

Hello why do i get *** - EVAL/APPLY: too many arguments given to F on function call with nested lists parameter. I cannot figure it out, since I passed a simple nested list.
(defun f (L)
(cond
((NULL l) nil)
((listp (car L))
(append (F(car L))) (F(cdr L) (car (F (car L)))))
(T (list(car L)))
)
)
(setq A '((1) 2 3))
(f A)
This better formatting should make it easy to spot the error:
(defun f (l)
(cond ((null l) nil)
((listp (car l))
(append (f (car l)))
(f (cdr l)
(car (f (car l)))))
(t (list (car l)))))
If that does not help, use SBCL to compile the function. It will give you a very clear error message.

Replacing sublists with their last element

(defun rep(list)
(format t"~a~%" list)
(cond
((null list) nil)
((atom (car list)) (cons (car list) (rep (cdr list))))
((listp (car list)) (cons (car (reverse (car list))) (cdr list)))
(t (rep list))
)
)
Write a function to replace each sublist of a list with its last element.
A sublist is an element from the first level, which is a list.
Example:
(a (b c) (d (e (f)))) ==> (a c (e (f))) ==> (a c (f)) ==> (a c f)
(a (b c) (d ((e) f))) ==> (a c ((e) f)) ==> (a c f)
I have the above problem to solve. Got it till one point but I'm stuck.
Apparently it doesn't go to the next elements in the list and I don't know why. Any ideas?
I would break it down like this:
(defun last-element (lst)
(if (listp lst)
(last-element (car (last lst)))
lst))
(defun rep (lst)
(when lst
(cons (last-element (car lst)) (rep (cdr lst)))))
then
(rep '(a (b c) (d (e (f)))))
=> '(A C F)
Did it without using map functions
(defun rep(list)
(cond
((null list) nil)
((listp (car list)) (rep (cons (car (reverse (car list))) (rep (cdr list)))))
(t (cons (car list) (rep (cdr list))))
)
)