What is happening in each line of this code? - scheme

I know the overall code is to return the last nth elements of the list, however, I don't understand the process, like in each line what is happening(and why, if possible)?
(define (last-n lst n)
(define (help-func lst drop)
(cond
((> drop 0)
(help-func (cdr lst ) (- drop 1)))
(else
(cdr lst ))))
(if (= (length lst ) n )
lst
(help-func lst (- (length lst ) 1 n ))))

There's a small bug, when n is greater than the length of the list you should return the whole list (or signal an error), I fixed it. Here's a break-down of the code:
(define (last-n lst n)
(define (help-func lst drop)
(cond
; iterate while there are elements to drop
((> drop 0)
; advance on the list, and we're one
; element closer to reach our target
(help-func (cdr lst) (- drop 1)))
(else
; else we reached the point we wanted, stop
(cdr lst))))
; if n is at least as big as the list
(if (>= n (length lst))
; return the whole list
lst
; else calculate how many elements
; we need to drop and start the loop
(help-func lst (- (length lst) 1 n))))
FYI, Racket already has this functionality, just use the take-right built-in procedure, it'll even be faster, requiring a single pass over the list (you're calling length a couple of times, and in a clever algorithm that would be unnecessary)

Related

How do you obtain the largest n elements of a list using Scheme?

I'm stuck on a homework question and could use any hints or suggestions. I need to find the n largest numbers in a list using Scheme. I am trying to do this by creating helper functions that are called by the main function. So far I have this:
(define (get_max_value L)
(if (null? L)
'()
(apply max L)
)
(define (biggest_nums L n)
(if (null? n)
'()
(cons (get_max_value L) (biggest_nums L (- n 1)))
)
)
When I type (biggest_num '(3 1 4 2 5) 3) at the command prompt drRacket just hangs and doesn't even return an error message. Where am I going wrong?
The simplest solution is to first sort the numbers in ascending order and then take the n first. This translates quite literally in Racket code:
(define (biggest_nums L n)
(take (sort L >) n))
It works as expected:
(biggest_nums '(3 1 4 2 5) 3)
=> '(5 4 3)
Two mains problems with your code:
L always stays the same. L doesn't decrease in size when you make the recursive call, so the max will always be the same number in every recursive call.
You don't ever check n to make sure it contains the correct amount of numbers before returning the answer.
To solve these two problems in the most trivial way possible, you can put a (< n 1) condition in the if, and use something like (cdr L) to make L decrease in size in each recursive call by removing an element each time.
(define (biggest-nums n L)
(if (or (empty? L)
(< n 1))
'()
(cons (apply max L) (biggest-nums (- n 1) (cdr L)))))
So when we run it:
> (biggest-nums 3 '(1 59 2 10 33 4 5))
What should the output be?
'(59 33 10)
What is the actual output?
'(59 59 33)
OK, so we got your code running, but there are still some issues with it. Do you know why that's happening? Can you step through the code to figure out what you could do to fix it?
Just sort the list and then return the first n elements.
However, if the list is very long and n is not very large, then you probably don't want to sort the whole list first. In that case, I would suggest something like this:
(define insert-sorted
(lambda (item lst)
(cond ((null? lst)
(list item))
((<= item (car lst))
(cons item lst))
(else
(cons (car lst) (insert-sorted item (cdr lst)))))))
(define largest-n
(lambda (count lst)
(if (<= (length lst) count)
lst
(let loop ((todo (cdr lst))
(result (list (car lst))))
(if (null? todo)
result
(let* ((item (car todo))
(new-result
(if (< (car result) item)
(let ((new-result (insert-sorted item result)))
(if (< count (length new-result))
(cdr new-result)
new-result))
result)))
(loop (cdr todo)
new-result)))))))

scheme mode"list" function

I'm trying to find the most repeated element in a list. The problem is I have to use the count function, which finds how many time a specific value is repeated in a list (for example, (count 7 '(4 8 9 2 4 8 9)) => 0, (count 2 '(4 8 9 2 2 4 8 9 2)) => 3).
I finished the count function and I think I'm close with the mode function. Any help will be appreciated.
(define (count item list)
(cond
[(null? list) '()]
[(= item (car list)) (+ 1 (count item (cdr list)))]
[#t (count item (cdr list))]))
(define (mode lst)
(cond
[(null? lst) '()]
[(> (count (car lst) lst) (mode (cdr lst))) (car lst)]
[else (mode (cdr lst))]))
It's mode night, as it seems - check a previous question, which uses a different approach: it assumes that the input list is sorted. But of course - the mode procedure can be implemented in terms of count with a non-sorted input list, although less efficiently - it's an O(n^2) solution:
(define (mode lnum)
(let loop ((lst lnum) ; list to traverse
(max-counter 0) ; number of times the mode appears
(max-current #f)) ; the mode
(if (null? lst) ; if the list is empty
max-current ; return the mode
(let ((n (count (car lst) lnum))) ; # of times current element appears
(if (> n max-counter) ; if it appears more times
(loop (cdr lst) n (car lst)) ; then we found a new maximum
(loop (cdr lst) max-counter max-current)))))) ; else continue
The idea is simple, count how many times is each element in the list, and keep track of the element which appears the most.
And FYI, neither this nor the other linked solutions (which require that a sort is performed before) implement the most efficient algorithm for finding a mode in an unsorted list. See this answer, the most-common procedure implemented there also computes the mode of a list, but in O(n).

Scheme return a list with first half of its elements

Write a procedure (first-half lst) that returns a list with the first half of its elements. If the length of the given list is odd, the returned list should have (length - 1) / 2 elements.
I am given these program as a example and as I am new to Scheme I need your help in solving this problem.
(define list-head
(lambda (lst k)
(if (= k 0)
'()
(cons (car lst)(list-head (cdr lst)(- k 1)))))))
(list-head '(0 1 2 3 4) 3)
; list the first 3 element in the list (list 0 1 2)
Also the expected output for the program I want is :
(first-half '(43 23 14 5 9 57 0 125))
(43 23 14 5)
This is pretty simple to implement in terms of existing procedures, check your interpreter's documentation for the availability of the take procedure:
(define (first-half lst)
(take lst (quotient (length lst) 2)))
Apart from that, the code provided in the question is basically reinventing take, and it looks correct. The only detail left to implement would be, how to obtain the half of the lists' length? same as above, just use the quotient procedure:
(define (first-half lst)
(list-head lst (quotient (length lst) 2)))
It looks like you are learning about recursion? One recursive approach is to walk the list with a 'slow' and 'fast' pointer; when the fast pointer reaches the end you are done; use the slow pointer to grow the result. Like this:
(define (half list)
(let halving ((rslt '()) (slow list) (fast list))
(if (or (null? fast) (null? (cdr fast)))
(reverse rslt)
(halving (cons (car slow) rslt)
(cdr slow)
(cdr (cdr fast))))))
Another way to approach it is to have a function that divides the list at a specific index, and then a wrapper to calculate floor(length/2):
(define (cleave_at n a)
(cond
((null? a) '())
((zero? n) (list '() a))
(#t
((lambda (x)
(cons (cons (car a) (car x)) (cdr x)))
(cleave_at (- n 1) (cdr a))))))
(define (first-half a)
(car (cleave_at (floor (/ (length a) 2)) a)))

how to delete third element in a list using scheme

This is what I want:
(delete-third1 '(3 7 5)) ==> (3 7)
(delete-third1 '(a b c d)) ==> (a b d)
so I did something like:
(define (delete-third1 LS ) (list(cdr LS)))
which returns
(delete-third1 '(3 7 5))
((7 5))
when it should be (3 7). What am I doing wrong?
Think about what cdr is doing. cdr says that "given a list, chop off the first value and return the rest of the list". So it's removing only the first value, then returning you the rest of that list (which is exactly what you are seeing). Since it returns a list, you don't need a list (cdr LS) there either.
What you want is something like this:
(define (delete-n l n)
(if (= n 0)
(cdr l)
(append (list (car l)) (delete-n (cdr l) (- n 1)))))
(define (delete-third l)
(delete-n l 2))
So how does this work? delete-n will delete the nth element of a list by keeping a running count of what element we are up to. If we're not up to the nth element, then add that element to the list. If we are, then skip that element and add the rest of the elements to our list.
Then we simply define delete-third as delete-n where it removes the 3rd element (which is element 2 when we start counting at 0).
The simplest way would be: cons the first element, the second element and the rest of the list starting from the fourth position. Because this looks like homework I'll only give you the general idea, so you can fill-in the blanks:
(define (delete-third1 lst)
(cons <???> ; first element of the list
(cons <???> ; second element of the list
<???>))) ; rest of the list starting from the fourth element
The above assumes that the list has at least three elements. If that's not always the case, validate first the size of the list and return an appropriate value for that case.
A couple more of hints: in Racket there's a direct procedure for accessing the first element of a list. And another for accessing the second element. Finally, you can always use a sequence of cdrs to reach the rest of the rest of the ... list (but even that can be written more compactly)
From a practical standpoint, and if this weren't a homework, you could implement this functionality easily in terms of other existing procedures, and even make it general enough to remove elements at any given position. For example, for removing the third element (and again assuming there are enough elements in the list):
(append (take lst 2) (drop lst 3))
Or as a general procedure for removing an element from a given 0-based index:
(define (remove-ref lst idx)
(append (take lst idx) (drop lst (add1 idx))))
Here's how we would remove the third element:
(remove-ref '(3 7 5) 2)
=> '(3 7)
This works:
(define (delete-third! l)
(unless (or (null? l)
(null? (cdr l))
(null? (cddr l)))
(set-cdr! (cdr l) (cdddr l)))
l)
if you want a version that does not modify the list:
(define (delete-third l)
(if (not (or (null? l)
(null? (cdr l))
(null? (cddr l))))
(cons (car l) (cons (cadr l) (cdddr l)))
l))
and if you want to do it for any nth element:
(define (list-take list k)
(assert (not (negative? k)))
(let taking ((l list) (n k) (r '()))
(if (or (zero? n) (null? l))
(reverse r)
(taking (cdr l) (- n 1) (cons (car l) r)))))
(define (delete-nth l n)
(assert (positive? n))
(append (list-take l (- n 1))
(if (> n (length l))
'()
(list-tail l n))))
(define (nth-deleter n)
(lambda (l) (delete-nth l n)))
(define delete-3rd (nth-deleter 3))

How to count the number of zeros in a list?

I'm new to Scheme, so can anyone give me an example? There's no local variable in Scheme, so how can I keep track of the number of zeros that being encountered.
I tried
#lang scheme
(define zeroes
(lambda (ll)
(cond ((null? ll)
0)
(else (= 0 (car ll))))
(zeroes (cdr ll))
)
)
But the compiler complained:
cdr: expects argument of type <pair>; given ()
Thanks,
Here's my solution (since the OP's already posted theirs):
(define (count-zeroes lst)
(let loop ((lst lst)
(count 0))
(cond ((null? lst) count)
((zero? (car lst)) (loop (cdr lst) (+ count 1)))
(else (loop (cdr lst) count)))))
Of course, no treatment of this subject can be considered complete without talking about fold, which is usually used to "summarise" a list down to a single object (like we're doing for this question):
(define (count-zeroes lst)
(fold (lambda (elem count)
(if (zero? elem) (+ count 1) count))
0 lst))
Just figured out the solution,
(define count
(lambda (lst)
(cond ((null? lst) 0)
((= 0 (car lst)) (+ 1 (count (cdr lst))))
(else (+ 0 (count (cdr lst))))
)
)
)
I'm keeping this at a hint level for now.
Your function is doing two things. First it computes 0 if its argument is an empty list, or #t or #f if its argument is a list that begins with 0 or not. Then it throws that result out and calls itself recursively on the rest of the list.
You're going to have to do two things to make this work: 1) combine the results of the individual zero tests somehow (for a thought experiment, look at your code; how would it ever return the value 2 if the list had two zeroes?); 2) "bottom out" successfully when it calls itself recursively on an empty list.

Resources