(define (num-zeroes lst)
(define (helper lst sofar)
(cond ((null? lst) sofar)
((list? (car lst)) (helper (car lst) sofar))
((eq? lst 0) (helper (cdr lst) (+ 1 sofar)))
(else
(helper (cdr lst) sofar))))
(helper lst 0))
This function is suppose to count the number of 0s in a list. However, it keeps giving me 0 when I input values. How would I be able to fix this?
In your third condition you are comparing lst to 0. This should be (car lst).
Because of your (list? (car lst)) condition it looks like you want to count nested lists. There is an issue with this in the current implementation (with the above check fixed) since the conditional does not add up separate parts of the list.
E.g.,
(num-zeroes '(0 0 (1 0) (1 0 0))) ; => 3
To fix this you can do something like this:
(define (num-zeroes lst)
(define (helper lst sofar)
(cond ((null? lst) sofar)
((list? (car lst)) (+ sofar ;; add sofar to
(helper (car lst) 0) ;; branched out first part
(helper (cdr lst) 0))) ;; and branched rest
((eq? (car lst) 0) (helper (cdr lst) (+ 1 sofar))) ;; (car lst), not lst
(else
(helper (cdr lst) sofar))))
(helper lst 0))
This leads to:
(num-zeroes '(0 0 (1 (1 (0 0) 0)) (1 0 0))) ;; => 7
Now, variations on your problem where you want to do something over a collection and keep an accumulated value happen a lot. fold is a higher-order function that is designed specifically for these problems.
Fold takes a function with two arguments (an element and an accumulator), a starting value and a collection. It successively applies the function to each element of the collection and at the end returns the accumulator.
In your case it's possible to only add 1 to the accumulator when the element is 0, and pass a flattened list (flatten removes the nesting from a list) to foldl (see https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._foldl%29%29) (the l means it walks the list from left to right) to deal with nesting:
(define (num-zeroes2 lst)
(foldl (lambda (e acc)
(if (= e 0)
(+ acc 1)
acc))
0
(flatten lst)))
This leads to the same result:
(num-zeroes2 '(0 0 (1 (1 (0 0) 0)) (1 0 0))) ;; => 7
Or, thinking about it, you can also flatten the list and filter out all values equal to 0 (there is a library method called zero? for that), and count the elements:
(define (num-zeroes3 lst)
(length
(filter zero? (flatten lst))))
Hope this helps.
Related
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.
Here is a task: a list is given, some of the elements are also lists. It's nescessary to replace the nested lists with the sum of the numbers in them, if all of them are even, using recursion. For example:
(1 2 NIL (2 4 6) 5 7) -> (1 2 NIL 12 5 7)
if the parent list matches the condition after the transformation:
(2 2 (4 4) (2 2)) -> (2 2 8 4) -> 16
Now i have the following code:
;; check for all list elements are even
(defun is-even-list (lst)
(cond ((null lst) t)
((and (numberp (car lst)) (evenp (car lst))) (is-even-list (cdr lst)))
(t nil)
)
)
;; list summing
(defun sum-list (lst)
(cond ((null lst) 0)
(t (+ (car lst) (sum-list (cdr lst))))
)
)
;; main func
(defun task (lst)
(cond ((null lst) nil)
((atom (car lst)) (cons (car lst) (task (cdr lst))))
((is-even-list (car lst)) (cons (list (sum-list (car lst))) (task (cdr lst))))
(t (cons (task (car lst)) (task (cdr lst))))
)
)
But now it processes only the “lowest” level of the list if it exists:
(2 4) -> (2 4)
(2 (2 4 6) 6) -> (2 12 6)
(2 (4 (6 8) 10) 12) -> (2 (4 14 10) 12)
(2 (4 6) (8 10) 12) -> (2 10 18 12)
How can i change this code to get "full" processing?
It's definitely not the best solution but it works:
(defun is-even-list (lst)
(cond ((null lst) t)
((and (numberp (car lst)) (evenp (car lst))) (is-even-list (cdr lst)))
(t nil)
)
)
(defun sum-list (lst)
(cond ((null lst) 0)
(t (+ (car lst) (sum-list (cdr lst))))
)
)
(defun test (lst)
(dotimes (i (list-length lst))
(cond
((not (atom (nth i lst))) (setf (nth i lst) (test (nth i lst))))
)
)
(cond
((is-even-list lst) (setf lst (sum-list lst)))
((not (is-even-list lst)) (setf lst lst))
)
)
Here's a solution which I think meets the requirements of the question: recursively sum a list each element of which is either an even number or a list meeting the same requirement. It also does this making only a single pass over the structure it is trying to sum. For large lists, it relies on tail-call elimination in the implementation which probably is always true now but is not required to be. sum-list-loop could be turned into something explicitly iterative if not.
(defun sum-list-if-even (l)
;; Sum a list if all its elements are either even numbers or lists
;; for which this function returns an even number. If that's not
;; true return the list. This assumes that the list is proper and
;; elements are numbers or lists which meet the same requirement but
;; it does not check this in cases where it gives up for other
;; reasons first: (sum-list-if-even '(2 "")) signals a type error
;; (but (sum-list-if-even '(1 "")) fails to do so)
(labels ((sum-list-loop (tail sum)
(etypecase tail
(null sum) ;all the elements of '() are even numbers
(cons
(let ((first (first tail)))
(etypecase first
(integer
;; Easy case: an integer is either an even number
;; or we give up immediately
(if (evenp first)
(sum-list-loop (rest tail) (+ sum first))
;; give up immediately
l))
(list
;; rerurse on the car ...
(let ((try (sum-list-if-even first)))
;; ... and check to see what we got to know if
;; we should recurse on the cdr
(if (not (eq try first))
(sum-list-loop (rest tail) (+ sum try))
l)))))))))
(sum-list-loop l 0)))
Allow me to show some improvements on your own answer.
First, use conventional formatting: no dangling parentheses, bodies indented two spaces, other argument forms aligned. Use appropriate line breaks.
(defun is-even-list (lst)
(cond ((null lst) t)
((and (numberp (car lst))
(evenp (car lst)))
(is-even-list (cdr lst)))
(t nil)))
(defun sum-list (lst)
(cond ((null lst) 0)
(t (+ (car lst)
(sum-list (cdr lst))))))
(defun test (lst)
(dotimes (i (list-length lst))
(cond ((not (atom (nth i lst)))
(setf (nth i lst) (test (nth i lst))))))
(cond ((is-even-list lst) (setf lst (sum-list lst)))
((not (is-even-list lst)) (setf lst lst))))
The first function checks two things: that every element is a number, and that every element is even. In this context, the first condition mainly means: no sublists.
(defun flat-all-even-p (list)
(and (every #'numberp list)
(every #'even list)))
The second function sums a list and assumes that all elements are numbers (sublists would signal an error here).
(defun sum (list)
(reduce #'+ list))
The third function does not test, it sums. Note that it only accidentally returns the answer, since setf returns the value it sets. Another problem is that you do index lookup on lists in a loop, which is very inefficient. Finally, you modify the list you were given, which will surprise your caller.
(defun sum-if-all-even (tree)
(if (listp tree)
(let ((recursed-tree (mapcar #'sum-if-all-even tree)))
(if (flat-all-even-p recursed-tree)
(sum recursed-tree)
recursed-tree))
tree)
(define (odds lst)
(if (null? lst)
lst
(cons (car lst)
(if (or (null? lst)
(not (pair? (cdr lst))))
'()
(odds (cddr lst)))))
)
This function returns the odd-numbered elements; my issue is, I want to take the list it returns and reverse it (using the built in reverse function). I've been trying to use lambda to store it but the results don't change, also tried using set-cons! also, to no avail. The concept of using let in a recursive function seems to escape me. If someone could point me in the right direction it would be very much appreciated!
Pass the function's result to reverse in the place where you want the reversed list:
> (odds '(a b c d e))
'(a c e)
> (reverse (odds '(a b c d e)))
'(e c a)
> (let ((o (reverse (odds '(a b c d e))))) (append o o))
'(e c a e c a)
> (define (reverse-odds ls) (reverse (odds ls)))
> (reverse-odds '(5 6 a 9 "hi"))
'("hi" a 5)
Here is a snippet storing both the return and the result using let*
(define (odds lst)
(if(null? lst)
lst
(cons (car lst)
(if (or (null? lst)
(not(pair? (cdr lst))))
'()
(odds (cddr lst))))))
(define data (odds `(1 2 3 4 5 6 7 8 9) ) )
(let ((rev_odds ( reverse data )))
;do stuff with results
(display rev_odds)
)
You can skip worrying about a return value if you just cons directly onto the recursive result
(define (odds lst)
(if (null? lst)
null
(if (odd? (car lst))
(cons (car lst)
(odds (cdr lst)))
(odds (cdr lst)))))
(odds '(0 1 2 3 4 5 6 7))
;; => '(1 3 5 7)
One way to represent a "return" value is by adding a parameter to our recursive function. Below we use acc in our auxiliary helper function, loop. Usage of parameters like this is one common way to move the recursive call into tail position
(define (odds lst)
(define (loop acc lst)
(if (null? lst)
(reverse acc)
(if (odd? (car lst))
(loop (cons (car lst) acc)
(cdr lst))
(loop acc
(cdr lst)))))
(loop null lst))
(odds '(0 1 2 3 4 5 6 7))
;; => '(1 3 5 7)
Another way is to represent our return value is by way of a lambda, cont below. We simply call cont with the value we wish to return. The recursive call looks a little more complicated in this case as we have to construct a lambda that represents the new return value. The added benefit here is odds constructs the result in order; reverse is no longer necessary
(define (odds lst (cont identity))
(if (null? lst)
(cont null)
(if (odd? (car lst))
(odds (cdr lst) (lambda (acc)
(cont (cons (car lst) acc))))
(odds (cdr lst) cont))))
(odds '(0 1 2 3 4 5 6 7))
;; => '(1 3 5 7)
I am currently confused with the idea behind functional programming in general. I currently have a working solution to my problem (That is, finding the min and max of a list, and returning these in a new list) but to do that, my solution essentially requires 3 functions, and this bothers me, because I am sure there is a way to do it with just 1 function in scheme.
So.. my question is, how do I combine the outputs of 2 functions into 1 concise function? (The driver function)
Here is what I have...
(define (findMax lst) ; Find and return maximum number in a list
(cond [(null? lst) '()]
[(= (length lst) 1) (list-ref lst 0)]
[(> (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMax (drop-right lst 1))]
[(< (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMax (cdr lst))]
(else
(findMax (cdr lst))
)
)
)
(define (findMin lst) ; Find and return smallest number in a list
(cond [(null? lst) '()]
[(= (length lst) 1) (list-ref lst 0)]
[(> (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMin (cdr lst))]
[(< (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMin (drop-right lst 1))]
(else
(findMin (cdr lst))
)
)
)
I use a driver function to take both of these functions, and make a new list shown here:
(define (findEnds lst)
(list (findMin lst) (findMax lst))
)
So essentially, if given a list:
(6 7 8 4 9 2)
the output would be:
(2 9)
I know there is some way to use lambda possibly to do all of this in 1 function, but I need to be pointed in the right direction. Thanks!
Here's my version (note that I've changed it to return the result as a single dotted pair, rather than a list with two elements†):
(define (min/max lst)
(if (empty? lst)
#f
(let ((next (min/max (cdr lst))))
(define cur (car lst))
(if (not next)
(cons cur cur)
(cons (min (car next) cur) (max (cdr next) cur))))))
Example:
> (min/max '(3 1 4 1 5 9))
(1 . 9)
† If you really want to use a list of two elements, change all the cons to list, and change the (cdr next) to (cadr next).
This is actually a really good challenge that might help with learning some Scheme concepts. I've implemented min/max using fold-left. It might also be fun using a named-let
(define (min/max lst)
(fold-left
(lambda (acc num)
(cons (min num (car acc)) (max num (cdr acc))))
(cons +inf.0 -inf.0)
lst))
I'm trying to write a code (function) using Scheme that:
Takes a list of any size as a parameter
Multiplies every number of the list together
Symbols should be skipped over
Values inside pairs should be included in multiplication
In other words, results should be as follows:
> (mult '(1 2 3))
6
> (mult '(1 2 x 3 4))
24
> (mult '(1 2 z (3 y 4)))
24 (mine gives me 2)
My code allows me to skip over the symbols and multiply everything. However, once I include a pair inside the list, it acts as though it isn't a number, therefore acting like it doesn't exist. Here's my code:
(define mult
(lambda (x)
(if (null? x)
1
(if(number? (car x))
(* (car x) (mult (cdr x)))
(mult(cdr x))))))
I've tried to use append when it finds a pair, but clearly I did it wrong... Any help on how I could get it to include the values inside a pair would be much appreciated.
i.e. '(1 2 y (3 z 4) = 1 * 2 * 3 * 4
You are nearly there, just missing the list? test:
(define (mult lst)
(if (null? lst)
1
(let ((ca (car lst)))
(cond
((number? ca) (* ca (mult (cdr lst))))
((list? ca) (* (mult ca) (mult (cdr lst))))
(else (mult (cdr lst)))))))
EDIT
He're an equivalent version without let:
(define (mult lst)
(cond
((null? lst) 1)
((number? (car lst)) (* (car lst) (mult (cdr lst))))
((cons? (car lst)) (* (mult (car lst)) (mult (cdr lst))))
(else (mult (cdr lst)))))
As you see, (car lst) is likely to be evaluated more than once, so I used let in the first version to avoid this.
It is a slightly advanced technique but this problem can easily be formulated as a tail recursive algorithm.
(define (mult lst)
(let multiplying ((lst lst) (r 1)) ; r is the multiplicative identity...
(if (null? lst)
r
(let ((next (car lst))
(rest (cdr lst)))
(multiplying rest (cond ((number? next) (* next r))
((list? next) (* (mult next) r))
(else r)))))))
> (mult '(1 2 3 a b (((((10)))))))
60
Using tail recursion has performance implications but, admittedly, it is not the first thing to learn - recursion is. However, in this case, because lists are often very long, avoiding a stack frame for each list element can be a dramatic savings; using tail calls avoids the stack frame.