Lisp recursion for split-list - recursion

(defun split-list (L)
(if (endp L)
'(nil nil)
(let ((x (split-list (cdr L))))
(list (cons (car L) (cadr x))(car X))
)))
This is the code which I have. It works fine:
(split-list '(1 2 3 4 5 6))
((1 3 5) (2 4 6))
But I need an explanation on the recursion part.
When we call the function (split-list (cdr L)) I am sure that it goes from 123456 to 23456. (car L) is 1
and (cadr X) is 3 but how did 5 came there ?
when function did
(split-list (cdr L)) didn't the x became 3456 and (cadr x) should be 4 ? which is wrong and same with other half. (car x) should be 3 now which is wrong.
Could anyone please explain ?

I would rewrite a recursive split-list as this:
(defun split-list (list)
(if (endp list)
(values nil nil)
(multiple-value-bind (split1 split2)
(split-list (rest list))
(values (cons (first list) split2)
split1))))
Above uses multiple values. The function returns the split result as two values. We also replace car with first and cdr with rest. The are just better names, but have the same functionality. multiple-value-bind binds the the two values of the recursive split-list call to the variables split1 and split2. The function values returns its two arguments as two values.
In the example below, you can see that the function indeed returns two values:
CL-USER 20 > (split-list '(a b c d e f))
(A C E)
(B D F)
You can trace its execution:
CL-USER 21 > (trace split-list)
(SPLIT-LIST)
CL-USER 22 > (split-list '(a b c d e f))
0 SPLIT-LIST > ((A B C D E F))
1 SPLIT-LIST > ((B C D E F))
2 SPLIT-LIST > ((C D E F))
3 SPLIT-LIST > ((D E F))
4 SPLIT-LIST > ((E F))
5 SPLIT-LIST > ((F))
6 SPLIT-LIST > (NIL)
6 SPLIT-LIST < (NIL NIL)
5 SPLIT-LIST < ((F) NIL)
4 SPLIT-LIST < ((E) (F))
3 SPLIT-LIST < ((D F) (E))
2 SPLIT-LIST < ((C E) (D F))
1 SPLIT-LIST < ((B D F) (C E))
0 SPLIT-LIST < ((A C E) (B D F))
(A C E)
(B D F)

Related

Scheme rotation function

I am trying to write a function in Scheme that returns all rotations of a given list. For example, (rotate '(a b c d e)) should return ((a b c d e) (b c d e a) (c d e a b) (d e a b c) (e a b c d)) (in some order).
I am not sure this would work:
(define (make-rotate alphabet) (lambda (x) (+ x alphabet)))
(define (same-arg-twice fn) (lambda (arg) (fn arg arg)))
(define (flip fn) (lambda (a b c d e) (fn b c d e a) (fn c d a e b) (fn d e a b c) (fn e a b c d)
(define (flip fn)
(lambda (3 9 5 8 2 4 7) (fn 9 4 3 2 4 7 8) (fn 3 2 4)
Start with a function that rotates a list once.
That is, it takes the list's first element and puts it at the back instead.
(define (rotate-once ls)
(append (cdr ls) (list (car ls))))
Test:
> (rotate-once '(a b c))
'(b c a)
Looks good.
Now we can use this on an already rotated list to produce the next rotation.
> (rotate-once (rotate-once '(a b c)))
'(c a b)
We could almost write this recursive procedure
(define (rotate ls)
(if (...)
'()
(cons ls (rotate (rotate-once ls)))))
but there is no useful condition for terminating the recursion.
We could depend on the length of the list, but I did this instead: make a helper function and pass it the list of elements that haven't been moved around yet.
When that list is empty, we're done.
(define (rotate-helper ls remaining)
(if (null? remaining)
'()
(cons ls (rotate-helper (rotate-once ls) (cdr remaining)))))
and now we can define
(define (rotate ls) (rotate-helper ls ls))
and
> (rotate '(a b c d e))
'((a b c d e) (b c d e a) (c d e a b) (d e a b c) (e a b c d))
(define (rotate lst)
(for/list ((_ lst))
(let ((tmp lst))
(set! lst (append (cdr lst) (list (car lst))))
tmp)))
> (rotate '(a b c d e))
'((a b c d e) (b c d e a) (c d e a b) (d e a b c) (e a b c d))
or:
(define (one-rotate lst)
(append (cdr lst) (list (car lst))))
(define (rotate lst)
(for/list ((_ lst))
(let ((tmp lst))
(set! lst (one-rotate lst))
tmp)))

How to look for an element in a list of lists in racket

I'm trying to find an element in a list of lists and print the lists that contain that element.
For the test: (search-table '((1 2 3) (4 2) (3 3 4) (5 3 2 1)) 1), the output is:
'((1 2 3) (5 3 2 1))
This is my code in DrRacket so far:
(define (search-table table item)
(if(equal? table null)
'()
(cons(search-table first table item))(search-table rest table item)))
But this code is giving me an error message which says:
if: bad syntax;
has 4 parts after keyword in: (if (equal? table null) (quote ()) (cons (search-table first table item)) (search-table rest table item))
Please help me with this as I am very new to Racket.
If the value is a member of the list, cons the list onto the result
(define (search-table lists value)
(cond ((null? lists) '())
((member value (car lists))
(cons (car lists) (search-table (cdr lists) value)))
(else (search-table (cdr lists) value))))
(search-table '((a b c d) (b c) (c d e f) (a b c)) 'a)
;; '((a b c d) (a b c))
You tagged this with tail-recursion tho, so let's do it with constant space
(define (search-table lists value)
(let loop ((lists lists) (acc null))
(cond ((null? lists) acc)
((member value (car lists))
(loop (cdr lists) (cons (car lists) acc)))
(else (loop (cdr lists) acc)))))
(search-table '((a b c d) (b c) (c d e f) (a b c)) 'a)
;; '((a b c) (a b c d))
But that result is in reverse order; according to your question anyway – we can "fix" that using a continuation as our accumulator instead of a list
(define (search-table lists value)
(let loop ((lists lists) (acc identity))
(cond ((null? lists)
(acc null))
((member value (car lists))
(loop (cdr lists) (lambda (rest)
(acc (cons (car lists) rest)))))
(else
(loop (cdr lists) acc)))))
(search-table '((a b c d) (b c) (c d e f) (a b c)) 'a)
;; '((a b c d) (a b c))
You tagged this with functional-programming tho, so let's do it using higher order functions
(define (search-table lists value)
(filter (lambda (list) (member value list))
lists))
(search-table '((a b c d) (b c) (c d e f) (a b c)) 'a)
;; '((a b c d) (a b c))

Group the elements of a set into disjoint subsets using iteration instead of recursion

I came across Pascal Bourguignon's solutions of the 99 Lisp problems and was wondering if his recursive solution of problem 27 using a nested mapcan-mapcar-construct could also be written using nested loops.
His solution is definitely very elegant:
(defun group (set sizes)
(cond
((endp sizes)
(error "Not enough sizes given."))
((endp (rest sizes))
(if (= (first sizes) (length set))
(list (list set))
(error "Cardinal mismatch |set| = ~A ; required ~A"
(length set) (first sizes))))
(t
(mapcan (lambda (combi)
(mapcar (lambda (group) (cons combi group))
(group (set-difference set combi) (rest sizes))))
(combinations (first sizes) set)))))
The function combinations is defined here as:
(defun combinations (count list)
(cond
((zerop count) '(())) ; one combination of zero element.
((endp list) '()) ; no combination from no element.
(t (nconc (mapcar (let ((item (first list)))
(lambda (combi) (cons item combi)))
(combinations (1- count) (rest list)))
(combinations count (rest list))))))
I started with a simple approach:
(defun group-iter (set sizes)
(loop :with size = (first sizes)
:for subgroup :in (combination size set)
:for remaining = (set-difference set subgroup)
:collect (list subgroup remaining) :into result
:finally (return result)))
which results in:
> (group-iter '(a b c d e f) '(2 2 2))
(((A B) (F E D C)) ((A C) (F E D B)) ((A D) (F E C B)) ((A E) (F D C B))
((A F) (E D C B)) ((B C) (F E D A)) ((B D) (F E C A)) ((B E) (F D C A))
((B F) (E D C A)) ((C D) (F E B A)) ((C E) (F D B A)) ((C F) (E D B A))
((D E) (F C B A)) ((D F) (E C B A)) ((E F) (D C B A)))
But now I am totally failing to implement the nesting which takes care of the further processing of remaining. As far as I understood there is always a way to express a recursion with a iteration but how does it look like here?

Common LISP function for calculate numbers and ignoring letters

I need to write for school a function that can calculate numbers and ignore the letters. Do I need to make a case for every operation? I don't know how to start. For example:
(+ 1 A 2 X) = (3 A X)
(- A 5 1 A) = 4
(* 2 C 0) = 0
So I have done a part of the problem. The 2 functions DELNUM and DELSYM are for deleting the numbers respectively the symbol from a list. It's all working now, just for example like (- A 5 A) -> 5 isn't, because I need some conditions for that.
(defun delnum (l)
(remove-if-not #'symbolp l))
(delnum '(4 S 56 h ))
;;-> (S H)
(defun delsym (l)
(remove-if-not #'numberp l))
(delsym '(+ a 1 2 3 b))
;;-> (1 2 3)
(defun test (l)
(cond
((null l) nil)
((case (car l)
(+ (cons (apply #'+ (delsym l)) (delnum (cdr l))))
(- (cons (apply #'- (delsym l)) (delnum (cdr l))))
(* (cond ((eql (apply #'* (delsym l)) 0) 0)
( t (cons (apply #'* (delsym l)) (delnum (cdr l))))))
(/ (cond ((eql (car (delsym l)) 0) '(error division by zero))
((eql (find 0 (delsym l)) 0) '(error division by zero))
(t (cons (apply #'/ (delsym l)) (delnum (cdr l))))))))))
(test '(/ 0 )) ;-> (ERROR DIVISION BY ZERO)
(test '(+ 1 2 A)) ;-> (3 A)
(test '(- 6 5 A C)) ;-> (1 AC)
(test '(- 1 5 A C X 0)) ;-> (-4 A C X)
(test '(* 0 5 A C)) ;-> 0
(test '(* 10 5 A C)) ;-> (50 A C)
(test '(/ 12 0 V 1 2)) ;-> (ERROR DIVISION BY ZERO)
(test '(/ S 3 7 C)) ;-> (3/7 S C)
(test '(+ -A A 5)) ;-> it gotta display 5 or (5)

printing elements of a list in racket

My question is how can i print the elements of a list two times, the code i have tried is given below
(define duplicate-list
(lambda (mylist n)
(cond ((null? mylist) '())
((< n 2) (cons (car mylist)
(duplicate-list mylist (+ n 1))))
(else
(duplicate-list (cdr mylist) 0)))))
(define duplicate
(lambda (mylist)
(duplicate-list mylist 0)))
The problem in this code is that, it works fine only when i give it a list as input, this fails to work when i give it an input of a nested list.
>(duplicate '(a 1 b 2 c 3 r x)) -> a a 1 1 b b 2 2 c c 3 3 r r x x
>(duplicate '( (a 1) b ((c)) 2)) ->((a 1) (a 1) b b ((c)) ((c)) 2 2)
Whereas, the expected outcome needed should be
(duplicate '( (a 1) b ((c)) 2 z 3) = ( (a a 1 1) b b ((c c)) 2 2 z z 3 3)
You're using the wrong approach to build the output list, you have to recur over the car and cdr parts, given that this is a list of lists. Try this:
(define (duplicate lst)
(cond ((null? lst)
'())
((not (pair? (car lst)))
(cons (car lst)
(cons (car lst) ; here we duplicate each element
(duplicate (cdr lst)))))
(else
(cons (duplicate (car lst))
(duplicate (cdr lst))))))
It works as expected:
(duplicate '((a 1) b ((c)) 2 z 3))
=> '((a a 1 1) b b ((c c)) 2 2 z z 3 3)
Here's another solution using pattern matching via match -
(define (duplicate l)
(match l
((list (list a ...) b ...) ; nested list
(cons (duplicate a)
(duplicate b)))
((list a b ...) ; flat list
(cons a
(cons a
(duplicate b))))
(_ ; otherwise
null)))
It works as expected -
(duplicate '((a 1) b ((c)) 2 z 3))
; '((a a 1 1) b b ((c c)) 2 2 z z 3 3)
(duplicate '())
; '()

Resources