Minimum level in a tree in Common lisp - list

I'm trying to write the code to find the minimum level in a tree (minimum number of nested sublists kinda)
The tree is given like this:
(A (B (E (I))(F))(C (G))(D))
which would look like:
A
/ | \
B C D
/\ |
E F G
|
I
Which would result... level 1. Max level is level 3 but I just need the minimum level.
I tried using the min function but whatever I do, it will either return 1 or 0 cause if the list is null, I return 0 and min (0 or anything) is always 0. Any ideas how to solve this without mapping/lambda funct?
I tried doing something like this:
(defun nrlevels (tail)
(cond
((null tail) 0)
((listp (car tail))
(min (+ 1 (nrlevels (car tail)))
(nrlevels (cdr tail))))
(t (nrlevels (cdr tail)))))
But as I said, that min will get to compare (Eventually) something with 0 and 0 being the minimum, the end result will be 0. I don't know how to escape this loop.

You are putting both the level recursion and the recursion that represents iteration over the children of a node into a single recursion. The problem is to distinguish between visiting nodes having no children and having reached the end of a children list.
You need to separate these things. I find it easiest to put the iteration over the children list into a loop:
(defun minimum-child-level (tree)
(if (atom tree)
0
(1+ (loop :for child :in tree
:when (listp child)
:minimize (minimum-child-level child)))))
or reduce:
(defun minimum-child-level (tree)
(if (atom tree)
0
(1+ (reduce #'min
(mapcar #'minimum-child-level
(remove-if-not #'listp tree))))))
EDIT: You could do it by interpreting a min accumulator and recursing one or the other way, but I do not recommend this for production code:
(defun minimum-child-level (tree &optional min-so-far)
(cond ((endp tree) ; end of child list
(if min-so-far
(1+ min-so-far) ; there were children
0)) ; no children
((atom (first tree)) ; ignore symbols, go to next child
(minimum-child-level (rest tree) min-so-far))
(t ; sublist
;; recurse into child
(let ((child-minlevel (minimum-child-level (first tree))))
;; go to next child
(minimum-child-level (rest tree)
(if min-so-far
(min min-so-far child-minlevel)
child-minlevel))))))

Related

create a list in c lisp recursively

I am trying to create a list in lisp that starts at n and ends at 2.
(setq liste ())
(defun makeList (n)
(if (> n 2)
(setq liste (append (makeList (- n 1)) liste)
(setq liste (append liste 2))))
This doesn't seem to work. Anybody help?
setq only changes a variable. You need to define it first. If you rely on a global variable then the second time around your result will have the elements of the previous run. It's very smelly!
;; With recursion
(defun my-make-list (start)
(if (< start 2)
'()
(cons start (my-make-list (1- start)))))
;; with tail recursion
(defun my-make-list (start)
(labels ((helper (cur acc)
(if (> cur start)
acc
(helper (1+ cur) (cons cur acc)))))
(helper 2 '())))
;; With loop
(defun my-make-list (start)
(loop :for n :from start :downto 2
:collect n))
The last one is best since CL doesn't guarantee tail call optimization. Notice that I do the tail recursive one in reverse since all lists are made from end to beginning.

New to Racket: why is the if statement affecting the return?

I just started learning Racket so I am still trying to figure out the intricacies of the language. I am trying to implement my own search function in a list. If the function finds it, it returns the index, otherwise it returns -1.
(define (find-index list item)
(if (equal? (length list) 1)
(if (equal? (first list) item) 0 1)
(if (equal? (first list) item)
0
(+ 1 (my-search (rest list) item)))))
So the find-index function is a recursive function that walks through the list looking for an item that is equivalent to "item." I have written it so that, if there are 4 elements in a list, the function can return any number between 0-4.
(define (my-search list item)
(define length (my-length list))
(define index (find-index list item))
(if (= index length) -1 index))
My idea is that if the find-index function returns a number equal to the list's length, it means the function did not find the item, therefore my-search function is supposed to return -1.
However, when I put in
(my-search (list "apple" "barbecue" "child" "demon" "enter") "fire")
the result I get is 3, instead of -1. If I print index before the if statement the index is 3 instead of 5. If
(if (= index length) -1 index))
is not part of the my-search function then everything is fine.
What I think is going on is that index is the id for the function itself, not the result of the function. However, I don't see why that effects the returning result of my-search. Is anyone willing to shed some light on this question?
Also, any style critique is welcome. I would like to know if I am not following conventions.
The weird behavior is caused by the fact that find-index is calling my-search which is calling find-index (a mutual recursion!). At some point, that extra if is causing the recursion to end prematurely. Solution: replace the call to my-search with find-index in the find-index procedure.
Now that that was settled, we can write a single procedure for finding an element's index in a list or signaling that it wasn't found, like this:
(define (find-index lst item)
(cond ((empty? lst) #f)
((equal? (first lst) item) 0)
(else
(let ((result (find-index (rest lst) item)))
(if result (add1 result) #f)))))
Let's see how the above improves your procedure:
The preferred way to structure a procedure with multiple conditions is to use a cond
You should not use list as a parameter name, it clashes with a built-in procedure with the same name
For the same reason, you should not call length a local definition
It's not a good idea to use length for checking if we stepped outside of a list, a well-built recursion will take care of that, without having to iterate over the list all over again
It's common to use #f to indicate that a search procedure didn't find what it was looking for
In a well-structured recursion over lists, you should check if a list is empty, normally this is the first base case we write - your procedure will fail if an empty list is passed
We use let to declare local variables, in this case it makes sense, to avoid calling the recursion twice
Use (add1 x), it's more idiomatic than (+ 1 x)
But wait, we can do better! The above solution can be rewritten in a tail-recursive style; by ensuring that the recursive call is the last thing we do, our procedure will use constant space, and it'll be as efficient as a loop in a conventional programming language. The trick is to pass an extra parameter with the value to return (in this case, the index). I'll use a named let for brevity:
(define (find-index lst item)
(let loop ((lst lst) (idx 0))
(cond ((empty? lst) #f)
((equal? (first lst) item) idx)
(else (loop (rest lst) (add1 idx))))))
You can verify that both procedures work as advertised:
(find-index (list "apple" "barbecue" "child" "demon" "enter") "fire")
=> #f
(find-index (list "apple" "barbecue" "child" "demon" "enter") "child")
=> 2
That's how I would attack the problem.
(define (find-index L item) ; L your list. item the item for which you want the index
(define (aux L res) ; Auxiliary function. L your list. item the item for which you want the index
(cond ((null? L) -1) ; No thing was found, return -1.
((eq? (car L) item) res) ; If the item is equal to the current item then return the position.
(else (aux (cdr L) (add1 res))))) ; Move on to the next item in the list and increment the position.
(aux L 0)) ; Call of the auxiliary function that will be doing the job
Test run...
(define L '(a b c d))
Element not in the list
(find-index L 'e)
Output : -1
Element "d"
(find-index L 'd)
Output : 3
Here is a version of find-index that attempts to use the same style as your original example. Instead of list I use xs (which is short for "list of xes").
Note that it would be better to use the false value #f to indicate "not found".
(define (find-index xs item)
(if (empty? xs)
-1 ; not found
(if (equal? (first xs) item)
0 ; found at beginning
(let ([index-in-rest (find-index (rest xs) item)]) ; index in rest of list
(if (= index-in-rest -1)
-1 ; not found in rest of list
(+ 1 index-in-rest)))))) ; add 1 because we skipped
the first element

racket: counting number of siblings

Having nested lists as the input, I'm trying to find how to output the number of 'siblings' an element has. In terms of trees, how many other leaf nodes belong to the same parent/root node.
My code is giving the wrong outputs (it's a really bad code) and I'm not sure how to entirely approach the question
(define (siblings lst n)
(cond
[(empty? lst) false]
[(member? n lst) (sub1 (length lst))]
[else (siblings (rest lst) n)]))
sample outcomes: if given (list (list 2 1) 3 (list 4)) and 3, produce 0
(list (list 1 2 3) (list (list 4 5 6 ))) and 5 -> 2
Your code has to do two separate things:
Find the branch that contains n
Count the number of siblings in that branch, accounting for the possibility of other branches starting there.
Finding the branch that contains n, assuming that n can only appear once:
(define (find-branch root n)
(cond ((empty? root) empty)
((memq n root)
root)
((list? (first root))
(let ((subresult (find-branch (first root) n)))
(if (not (empty? subresult))
subresult
(find-branch (rest root) n))))
(else (find-branch (rest root) n))))
Since you're using "Beginning Student," that takes all the tools out of your toolbox. Fortunately, it still has number?, so if it's safe to assume that anything that isn't a number in this assignment is a list, you can define list? like this:
(define (list? n) (not (number? n)))
Given your example tree as input, it would return:
(4 5 6)
The above example unnecessarily uses memq repeatedly on the rest of the
input list as a result of using recursion to iterate over the same list.
Here's a more efficient version of the above, but you can't implement it in Beginning Student:
(define (find-branch root n)
(cond ((empty? root) false)
((memq n root) root)
(else (foldl (λ (a b)
(if (empty? a) b a))
empty
(map (λ (sublist)
(find-branch sublist n))
(filter list? root))))))
You pass the result of that to a function to count the siblings. I previously provided a version that would work in the real Racket, but not the Beginning Student version used by teachers:
(define (count-siblings root mem)
(count (λ (sib)
(and (not (eq? sib mem))
(not (list? sib)))) root))
Here's a version that's compatible with Beginning Student:
(define (count-siblings lst n counter)
(cond
[(empty? lst) counter]
[(and (not (list? (first lst)))
(not (eq? n (first lst))))
(count-siblings (rest lst) n (add1 counter))]
[else (count-siblings (rest lst) n counter)]))
Finally, put the two together:
(define (find/count-siblings root n)
(count-siblings (find-branch root n) n 0))

Depth of list in scheme

I'm trying to write a program in scheme that will find the maximum depth of a list. My code so far is:
(define (depth l)
(define (helper l count)
( cond
((null? l) count)
((not(list? (car l))) (helper (cdr l) count))
(else (helper (car l) (+ count 1)) )
)
)
(helper l 1)
)
It works for lists of this type (depth '(1 2 3 (2))) -> 2, but obviously not for list of the type (depth '( (2) ((3))) -> 3. The problem is that when I first encounter a list, I automatically jump to it increment the count and call it recursively again, ignoring the other elements of the list. I want to fix this problem and I thought of adding another variable temp which to hold the current count for each element in the list and check if it is bigger than count and if it is true I set! count to temp, but again I have a problem with the recursion. My other idea was to use another list in which to append count on every step and find the maximum value in that list, but I couldn't realize that too. Any ideas how to do this problem?
Here's an implementation using map:
(define (max-depth l)
(define (helper depth el)
(cond
[(null? el) (add1 depth)]
[(list? el)
(apply max
(map (curry helper (add1 depth))
el))]
[else depth]))
(helper 0 l))
While I think this implementation is fairly elegant, it admittedly is not tail-recursive.
Here is a slightly more complex, breadth-first tail-recursive implementation:
(define (max-depth l)
(define (helper depth els)
(define remaining (filter list? els))
(if (zero? (length remaining))
depth
(helper (add1 depth) (apply append remaining))))
(helper 1 l))

How to print the largest and lowest value in a nested list in Lisp

I'm trying to develop a simple function that returns the smallest and largest value in Lisp. So far I have the basic solution working for a single Lisp and here is the code
(defun get-smallest-large (lst &optional (smallest 0) (largest 0))
(setf smallest (first lst))
(setf largest 0)
(dolist (nxt lst)
(if (< nxt smallest)
(setf smallest nxt)
(if (> nxt largest)
(setf largest nxt))))
(cons smallest largest))
This works like:
(defun get-smallest-large '(1 2 -1 3))
= (-1 . 3)
Now, I can't for the life of me figure out how to change this solution to deal with nested lists so for instance, I entered this:
(defun get-smallest-large '(5 (-2 20 (3)) -6 (-7 13)))
= (-7 . 20)
How would I go about this?
Here's one way you can approach it: when you recurse into sublists, process the return values as if they were elements of the outer list also. Example (in Scheme, which is my "native language"; requires SRFI 26):
(define (min-max x (min #f) (max #f))
(cond ((null? x) (if min (values min max) (values)))
((cons? x) (call-with-values (cut min-max (car x) min max)
(cut min-max (cdr x) <...>)))
(else (values (if (and min (< min x)) min x)
(if (and max (> max x)) max x)))))
And here's a direct Common Lisp translation of same, by which I mean that it's not idiomatic CL at all, but presented for CL programmers unfamiliar with Scheme to get an idea of what the Scheme code does. In particular, the Scheme requirement for proper tail recursion still holds, even though CL does not provide that.
(defun min-max (x &optional min max)
(cond ((null x) (if min (values min max) (values)))
((consp x)
(multiple-value-call #'min-max (cdr x) (min-max (car x) min max)))
(t (values (if (and min (< min x)) min x)
(if (and max (> max x)) max x)))))
Your code assumes that all the elements of the list are numbers. But if you have a nested list, then the list can contain lists of numbers, or lists of lists of numbers and so on.
Your list processing loop has to inspect the type of each element and handle that accordingly.
If you see a list, you want to make a recursive call to get-smallest-large to fetch the smallest and largest value from just that list. In the recursive call, you pass those extra two parameters, so that the function will not return a smaller maximum than you have already seen or larger minimum.
Since the return value is a cons, the recursive call might look something like this:
(destructuring-bind (sm . la) (get-smallest-large smallest largest)
(setf smallest sm largest la))
In Common Lisp, functions can return multiple values; code which returns a pair of numbers as a cons looks like something that was a quick and dirty port of code from a Lisp dialect without multiple value support.
This means that instead of returning (cons smallest largest) (return a single value which is a cell holding two numbers) we can return (values smallest largest) (actually return two values). The recursive call which uses the values then condenses to:
(multiple-value-setq (smallest largest) (get-smallest-large smallest largest))
The two setf calls at the beginning of the function will destroy the correctness of the recursion. If the function is given smallest and largest values on entry, it must honor those values and not simply overwrite them by taking an arbitrary value from the list structure. That code also has another problem in that it assumes that (first lst) is a number. It could be a sublist! And yet another problem: the list could be empty!!!
I suggest doing it like this:
(defun get-smallest-large (list &optional smallest largest)
;;
)
That is, default smallest and largest to nil, and deal with nil in the rest of the code as indicating "smallest or largest value not known yet". For instance:
;; the number we are looking at is smallest so far, if we have not
;; seen any number before, or if it is smaller than the smallest one we have
;; seen so far.
(if (or (null smallest) (< nxt smallest))
(setf smallest nxt))
This will also fix another bug. Think about what your function should return if it is called on an empty list. Surely not (0 . 0): zero does not occur in an empty list. A reasonable representation to return in that case is (nil . nil) which indicates that lowest and highest number are not known.
Here's a version that avoids recursion and uses a nice Common Lisp library: iterate:
(ql:quickload :iterate)
(use-package :iterate)
(defun minmax (tree)
(iter
(with head := tree)
(with stack := nil)
(while (or head stack))
(cond
((and (null head) stack)
(setf head (cdr (pop stack))))
((consp (car head))
(push head stack)
(setf head (car head)))
((car head)
(minimize (car head) :into min)
(maximize (car head) :into max)
(setf head (cdr head))))
(finally (return (values min max)))))
This would be a preferred way of doing it for very large, deeply nested trees, it trades some complexity and O(log n) space (used for backtracking) for scalability (other version suggested here would fail to perform on sufficiently large trees, where the limit would be the memory allocated per thread by the Lisp implementation to the stack of this function.)
The benefit of recursive version, however, may be that in principle, it would be easier to make it run several computations in parallel.
Using some macro-magic you can then hide the uninteresting bits of the original minmax function (those which only deal with iterating over tree):
(defmacro-clause (FOR var IN-TREE tree)
"Iterates over TREE in depth-first order"
(let ((stack (gensym)) (head (gensym)))
`(progn
(with ,head := ,tree)
(with ,stack := ,nil)
(with ,var := ,nil)
(while (or ,head ,stack))
(cond
((and (null ,head) ,stack)
(setf ,head (cdr (pop ,stack)))
(next-iteration))
((consp (car ,head))
(push ,head ,stack)
(setf ,head (car ,head))
(next-iteration)))
(setf ,var (car ,head) ,head (cdr ,head)))))
(defun minmax (tree)
(iter
(for leaf :in-tree tree)
(minimize leaf :into min)
(maximize leaf :into max)
(finally (return (values min max)))))
And have much leaner function, which only shows the important parts.
And here's the parallel version of the algorithm using lparallel library:
(ql:quickload :lparallel)
(setf lparallel:*kernel* (lparallel:make-kernel 128))
(lparallel:defpun pminmax (tree &optional min max)
(labels ((%min (&rest numbers)
(iter (for i :in numbers) (when (numberp i) (minimize i))))
(%max (&rest numbers)
(iter (for i :in numbers) (when (numberp i) (maximize i)))))
(cond
((null tree) (cons min max))
((consp (car tree))
(lparallel:plet
((head (pminmax (car tree) min max))
(tail (pminmax (cdr tree) min max)))
(cons (%min (car head) (car tail) min)
(%max (cdr head) (cdr tail) max))))
(t (destructuring-bind (new-min . new-max)
(pminmax (cdr tree) min max)
(cons (%min (car tree) new-min min)
(%max (car tree) new-max max)))))))
Unfortunately, lparallel doesn't yet implement an alternative for multiple-value-bind, so we had to combine the results into a cons cell, but given some persistence it would be possible to implement the parallel version of the above macro and get rid of this unfortunate limitation (which is left as an exercise for the reader).
Use the well known function flatten to flatten first your nested list, before you apply your own minimax function on it.
(defun flatten (x)
(cond ((null x) nil)
((atom x) (list x))
(t (append (flatten (car x))
(flatten (cdr x))))))
Then apply:
(get-smallest-large (flatten '(5 (-2 20 (3)) -6 (-7 13))))
;; returns: (-7 . 20)
It works, because
(flatten '(5 (-2 20 (3)) -6 (-7 13)))
;; returns: (5 -2 20 3 -6 -7 13)
Since the list is flat, you can apply your original function on it.
Using flatten, you can write a universal get-smallest-large* function, which works both with nested and flat lists:
(defun get-smallest-large* (lst &optional (smallest 0) (largest 0))
(get-smallest-large (flatten lst) smallest largest))
;; now you call on any lists - flat or nested:
(get-smallest-large* '(5 (-2 20 (3)) -6 (-7 13)))
If the list is huge, you have to think of generator lists and generator flatten.
This is explained here https://www.cs.northwestern.edu/academics/courses/325/readings/list-gen.php