racket: counting number of siblings - list

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))

Related

Replacing a certain number of repeated elements in a list in Racket

I am trying to define the rule 3 of "MIU System" of "Gödel, Escher, Bach" (Douglas Hofstadter), which says:
Replace any III with a U
Example:
MIIIIU → MUIU and MIIIIU → MIUU
Main code:
(define (rule-tree lst)
(if (<= 3 (counter lst #\I))
(append (delete #\I lst) (list #\U))
(append lst empty)))
(define (delete x lst)
(cond [(empty? lst) lst]
[(eq? (first lst) x) (delete x (rest lst))]
[else (append (list (first lst)) (delete x (rest lst)))]))
(define (counter lst target)
(if (empty? lst)
0
(+ (counter (rest lst) target)
(let ((x (first lst)))
(if (list? x)
(counter x target)
(if (eqv? x target) 1 0))))))
With this expression there is no problem:
>(rule-tree '(#\M #\I #\I #\I))
'(#\M #\U)
But I don't know how to determine the position that the "U" should take when finding the 3 "I".
Any suggestion will be very helpful :)
Here is an alternative recursive version, where repl2 encodes the information “we have just encountered one #\I”, while repl3 encodes the information “we have just encountered two #\I”:
(define (repl lst)
(cond ((empty? lst) lst)
((eqv? (first lst) #\I) (repl2 (rest lst)))
(else (cons (first lst) (repl (rest lst))))))
(define (repl2 lst)
(cond ((empty? lst) (list #\I))
((eqv? (first lst) #\I) (repl3 (rest lst)))
(else (cons #\I (cons (first lst) (repl (rest lst)))))))
(define (repl3 lst)
(cond ((empty? lst) (list #\I #\I))
((eqv? (first lst) #\I) (cons #\U (repl (rest lst))))
(else (cons #\I (cons #\I (cons (first lst) (repl (rest lst))))))))
Of course this solution is some kind of hack and cannot scale to a greater number of repetitions. But looking at the structure of this solution and simply generalizing the three functions we can produce a general solution:
(define (repl lst n from to)
(define (helper lst k)
(cond ((empty? lst) (repeat from (- n k)))
((eqv? (first lst) from)
(if (= k 1)
(cons to (helper (rest lst) n))
(helper (rest lst) (- k 1))))
(else (append (repeat from (- n k))
(cons (first lst) (helper (rest lst) n))))))
(define (repeat x n)
(if (= n 0)
'()
(cons x (repeat x (- n 1)))))
We define a function repl that takes a list, the number of copies to replace (n), the element to replace (from) and the element that must be substituted (to). Then we define a helper function to do all the work, and that has as parameters the list to be processed and the number of copies that must be still found (k).
Each time the function encounters a copy it checks if we have finished with the number of copies and substitutes the element, restarting its work, otherwise it decrements the number of copies to find and continues.
If it founds an element different from from it recreates the list with the elements “consumed” until this point (maybe 0) with repeat and then continues its work.
Note that the previous version of the helper function had an error in the final case, when lst is null. Instead of returning simply the empty list, we must return the possibly skipped from elements.

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))

Finding the occurence element in the list in racket

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.

Having a hard time with delete-ing every nth element in Lisp?

Trying to learn lisp, want to delete every nth. I only managed to delete the first (nth) element
(defun delete-nth (n list)
(if (zerop n)
(cdr list)
(let ((cons (nthcdr (1- n) list)))
(if cons
(setf (cdr cons) (cddr cons))
cons))))
I'd like to delete the next nth and so on
Also I tried this:
(defun remove-nth (list n)
(remove-if (constantly t) list :start n :end (+ 1 n)))
No idea how to start again
What I was thinking was concatenating, but I have no idea of how to keep track of my position.
Counting from 1 (changing to 0 is trivial):
(defun remove-every-nth (n list)
(loop for element in list
for index from 1
unless (zerop (rem index n))
collect element))
Also: Please indent your code correctly.
An alternative way to do the same thing:
(defun remove-all-nth (list period)
(remove-if
(let ((iterator 0))
(lambda (x)
(declare (ignore x))
(= 0 (mod (incf iterator) period)))) list))
(remove-all-nth '(1 2 3 4 5 6 7 8 9 0) 3)
; (1 2 4 5 7 8 0)
Perhaps a more academic recursive solution here:
(defun delete-nth (n list)
(labels ((rec (i list)
(cond ((null list) nil)
((= i 1) (rec n (cdr list)))
(t (cons (car list) (rec (1- i) (cdr list)))))))
(rec n list)))
But in real life I'd use the loop option above.

Scheme List Derangement (Rearrangement of sorts)

im trying to write a function in Scheme where i accept a list and return all the different derangements (look below for definition) as a list of lists
derangement: A list where no item is in the same place as the original list
ex: '(a b c) -> '(cab)
any help is appreciated!
Compute all of the permutations of the input list and then filter out the ones that have an element in the same position as the input list. If you need more detail, leave a comment.
Edit 1:
Define (or maybe it's defined already? Good exercise, anyway) a procedure called filter that takes as its first argument a procedure p and a list l as its second argument. Return a list containing only the values for which (p l) returns a truthy value.
Define a procedure derangement? that tests if a list l1 is a derangement of l2. This will be handy when paired with filter.
The most obvious solution would be something like this:
(define filtered-permutations
(lambda (lst)
(filter
(lambda (permuted-list)
(deranged? permuted-list lst))
(permute lst))))
Since the number of derangements is considerably lower than then number of permutations, however, this is not very efficient. Here is a solution that mostly avoids generating permutations that are not derangements, but does use filter once, for the sake of simplicity:
(define deranged?
(lambda (lst1 lst2)
(if (null? lst1)
#t
(if (eq? (car lst1) (car lst2))
#f
(deranged? (cdr lst1) (cdr lst2))))))
(define derange
(lambda (lst)
(if (< (length lst) 2)
;; a list of zero or one elements can not be deranged
'()
(permute-helper lst lst))))
(define derange-helper
(lambda (lst template)
(if (= 2 (length lst))
(let ((one (car lst))
(two (cadr lst)))
(filter
(lambda (x)
(deranged? x template))
(list (list one two) (list two one))))
(let ((anchor (car template)))
(let loop ((todo lst)
(done '())
(result '()))
(if (null? todo)
result
(let ((item (car todo)))
(if (eq? item anchor)
;; this permutation would not be a derangement
(loop (cdr todo)
(cons item done)
result)
(let ((permutations
(map
(lambda (x)
(cons item x))
(derange-helper (append (cdr todo) done)
(cdr template)))))
(loop (cdr todo)
(cons item done)
(append result permutations)))))))))))