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))
Related
Another question of logic, the task is to find the depth of a list, for example: given a list of (A B (C D (E))) it should somehow indicate that the depth is 2 (or 3 if you include the base list). I am restricted to a set of common Racket functions of which I will list below. Where I am at I can iterate through the list but end up halting at the first sub-list, i.e: (A (B (C)) (D (E (F)))) comes out as only 2.
Here is the list of functions available:
cons, car, cdr, define, quote, if, cond, else
Basic forms of arithmetic (+, -, *, /)
Very basic tests (null?, list?, eq?, numeric comparisons)
Here is my definition so far, I would really appreciate if someone could just shift me in the right direction.
(define (len l) (if (null? l) 0 (+ 1 (len (cdr l)))))
(define A '(A (B) (C (D))))
(define (depth l) (cond
[(null? l) '()]
[(list? (car l)) (cons (car l) (depth (car l)))]
[else (depth (cdr l))]
))
(depth A)
(len (depth A))
Here is my definition in Common Lisp
(defun list-depth (list &optional (depth 0))
(cond ((null list) depth)
((atom (first list)) (list-depth (rest list) depth))
(t (max (list-depth (first list) (1+ depth))
(list-depth (rest list) depth)))))
I don't have Racket installed on this computer, so here is an untested translation to Scheme/Racket:
(define (list-depth lst depth)
(cond ((null? lst) depth)
((not (list? (car lst)) (list-depth (cdr list) depth))
(else (max (list-depth (car lst) (+ 1 depth))
(list-depth (cdr lst) depth)))))
Logic is as follows:
If the list is empty, return current depth.
If the car of the list is atom (not list), it won't increase the depth, find the depth of the rest (cdr) of the list.
Otherwise, the depth is going to be the maximum between the +1 depth of car (remember, it is the list now) and the depth of the cdr of the list. Notice increase of the depth for car and not for cdr.
Pre-defined procedures used: +, max, null?, list?, car, cdr, not.
In my answer here, lists start with a depth of 0 and increase by 1 for each level of nesting. If you'd like for them to start with a depth of 1, you can change (y 0) to (y 1) in the list-depth procedure
This can be implemented with a straightforward fold
(define (list-depth xs (y 0))
(foldl (λ (x z)
(if (list? x)
(max z (list-depth x (+ 1 y)))
(max z y)))
y
xs))
foldl has a simple implementation of
(define (foldl f y xs)
(if (null? xs)
y
(foldl f (f (car xs) y) (cdr xs))))
Here's some outputs
(list-depth '()) ; ⇒ 0
(list-depth '(A)) ; ⇒ 0
(list-depth '(A (B))) ; ⇒ 1
(list-depth '(A (B (C)))) ; ⇒ 2
(list-depth '(A (B (C (D (E)))) (B (C)) (B))) ; ⇒ 4
If you don't want to use the fold abstraction, you can expand the fold within list-depth to
;; THIS CODE IS BROKEN, DO NOT USE
;; #mobiuseng found bugs
(define (list-depth xs (y 0))
(cond
[(null? xs) y]
[(list? (car xs))
(max y (list-depth (car xs) (+ 1 y)))]
[else
(max y (list-depth (cdr xs) y))]))
Both result in the same output, but in this implementation, the two concepts of folding and max are tangled together. Seeing the guts of the fold makes it much harder to read this answer compared to the first one.
The guts of the fold made it easy for bugs to hide in this last snippet. I can't suggest writing this way in the first place, so I'm not going to bother spending effort to fix it.
Every list is built of a current element, under its car, and the rest of the list, under the cdr.
The depth of the list is the same as depth of the rest of the list, if that's the deepest.
The depth of the list is one more than the depth of its car, if that's the deepest.
So,
(define (depth lst)
(define a-depth (+ 1 (depth (car lst))))
(define d-depth (depth (cdr lst)))
(if (< ..... ) .....
; or else
...... ))
And of course, don't forget to handle the case when the list is empty, or an atom (not a pair — you can't call car or cdr with a non-pair argument, it would cause an error if you did):
The depth of an empty list is zero.
The depth of an atom is zero.
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))
Assume (list "apple" "orange" "apple" "grape" "orange")and produce (list (list 2 "apple") (list 2 "orange") (list 1 "grape")).
The most common fruit will occur first in the produced list.
In the case of ties, order the tied pairs with the fruit in increasing alphabetical order.
use abstract list function such as map,filter, foldr and quicksort in local. no recursion.
i'm not sure how to do it without recursion.
i wrote like this:
(define (function list)
(cond
[(empty? list) empty]
[else
(local
(define (helper1 a b)
(cond
[(equal? a b) a]
[else b]))
(define T (foldr helper1 (first list) (rest list)))
(define (count a)
(cond
[(equal? a T) true]
[else false]))
(define new-list (quicksort (length (filter count list)) >))]
The most efficient way is to use a (mutable) hash table:
(define (count-by-type lst)
; create hash
(define h (make-hash))
; update hash, creating entries if needed, otherwise adding 1 to existing entry
(map (lambda (e) (hash-update! h e add1 0)) lst)
; create list of (count key) elements from hash and sort accordingly
(sort (map (lambda (e) (list (cdr e) (car e))) (hash->list h))
(lambda (x y) (or (> (car x) (car y))
(and (= (car x) (car y)) (string<? (cadr x) (cadr y)))))))
testing:
> (count-by-type (list "apple" "orange" "apple" "grape" "orange"))
'((2 "apple") (2 "orange") (1 "grape"))
I just rehashed my own answer from a previous question. This seems to be a similar assignment, but without struct
Using a hash you could do it with only one pass through the unsorted list, then produced a list that then was sorted with a special <-function that sorts by count, then fruit.
These hints are for a functional solution. First sort the argument (sort list-of-fruits string>?). that the in descending order and oposite of your result. .
Given the list has at least one element:
(let rec ((cur (car sorted-fruits)) (cnt 1) (lst (cdr sorted-fruits)) (acc '()))
(cond ((equal? cur (car lst)) (rec cur (add1 cnt) (cdr lst) acc))
(else (rec (car lst) 1 (cdr lst) (cons (list cnt cur) acc)))))
This will produce a list in ascending order with counts.
If you sort again:
(sort list-of-counts-and-fruit (lambda (x y) (>= (car x) (car y)))
sort in Racket is stable. That means if you have two with equal counts in the list they will end up in their original order. The original order was the ascending animal order so the result is ordered by count descending, then name ascending.
I guess your procedure can be made by chaining these together, perhaps using let to store intermediates to make expressions shorter and more readable.
I'm attempting to make a procedure named median that takes the median value of a list. If the list is even, then I will return the two middle numbers. I have the logic all thought out in my head, but I'm not sure how to complete it. NOTE: I am trying to avoid using list-ref, as it would trivialize the problem.
So far, my code looks like the following.
(define (median lst)
(if (null? lst)
'()
(if (even? lst) ; ends here
Now, my approach to the problem is this.
Odd #- Return the value of the "car#" that's in place of (/ (+ (length lst) 1) 2)
3; 2nd car (1 100 3) => 100
5; 3rd car (1 2 100 4 5) => 100
7; 4th car (1 2 3 100 5 6 7) => 100
Even # - Return the value of the "car#" that's in place of (/ (length lst) 2) AND (+ (/ (length lst) 2) 1)
2; 1st and 2nd car (1 2) => 1 2
4; 2nd and 3rd car (1 20 30 4) => 20 30
However, I cant seem to come up with a way that could recursively implement this pseudocode.
EDIT: Not sure if anyone is still out there willing to help, but I ended up writing an iterative procedure that will take the median index value for any odd list. My trouble now is implementing something that will make the code work for an even list, and also something that doesn't return the value in a list:
(define (median-index-odd lst)
(define (median-index-iter1 lst times_carred)
(if (null? lst)
'()
(if (= times_carred (/ (+ (length lst) 1) 2))
(list (car lst))
(median-index-iter1 (cdr lst) (+ 1 times_carred)))))
(median-index-iter1 lst 0))
I've also came up with a seperate procedure for finding the median index when the list is even:
(define (median-index-even lst)
(define (median-index-iter2 lst times_carred)
(if (null? lst)
'()
(if (= times_carred (/ (length lst) 2))
(list (car lst) (cadr lst))
(median-index-iter2 (cdr lst) (+ 1 times_carred)))))
(median-index-iter2 lst 0))
Seems like homework.
The straightforward solution includes list-sort (rnrs / sorting) unless it's already sorted, length to get the list length, list-tail to get the list from half and car for odd, and an additional cadr for the even list. You use let to do something with intermediate values.
Edit in some code even if you get it right or not. For the latter we can help you more.
(define (median L)
(if (null? L)
(error "No median of empty list")
(let loop ((L1 L) (L2 L))
(cond ((null? (cdr L2)) (car L1))
((null? (cddr L2)) (list (car L1) (cadr L1)))
(else (loop (cdr L1) (cddr L2))))))
split into two lists take the first one at a time, the second two at a time
I'm making a program that takes a list and a sum. If some of the numbers in the list add up to the sum, it returns true. Else, return false. It seems to be working for some cases but not for others. For example,
if I input this:
(numlist-sum '(5 9) 9)
It should return true because one of the numbers (9) equals the sum (9). But, for some reason, its returning false.
I can't figure out what the problem is. Help please?
(define (numlist-sum? ls sum)
(if (null? ls) #t
(if (and (null? (cdr ls)) (equal? (car ls) sum)) #t
(if (equal? (car ls) sum) #t
(if (equal? (cdr ls) sum) #t
(if (equal? (apply + (car ls) (cdr ls)) sum) #t
#f))))))
I'll give you some hints for solving this problem (looks like homework). First write a procedure that generates all the possible subsets of the list (e.g., the power set of the list). For example:
(powerset '(1 2 3))
=> '(() (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3))
With the above procedure in hand (and it's easy to find the algorithm, Google is your best friend), simply iterate over each of the sublists and sum its values:
(apply + '(2 3))
=> 5
If one of the sublists' sum equals the expected value, return #t. If none of the sums satisfy the expected value, return #f.
EDIT:
I forgot to mention, this is a well-known problem - it's the subset sum problem, which can be efficiently solved (at least, more efficiently than generating the power set) using dynamic programming. But I don't think that's the goal of this homework in particular.
Here is a solution that checks each element one by one and then recurses down the list if the first element isn't the sum.
(define (numlist-sum list sum)
(and (not (null? list))
(let ((head (car list)))
(cond ((number? head)
(or (= sum head)
(numlist-sum (cdr list) sum)))
((list? head)
(or (= sum (apply + head))
(numlist-sum (cdr list) sum)))
(else 'ill-formed-list)))))
Also, note that your code can be rewritten as:
(define (numlist-sum? ls sum)
(or (null? ls)
(if (and (null? (cdr ls)) (equal? (car ls) sum))
(equal? (car ls) sum)
(equal? (cdr ls) sum)
(equal? (apply + (car ls) (cdr ls)) sum)))
I'd say the use of '(if pred #t else ...) is a bit awkward and hides the true logic of the code.