Scheme mode function - functional-programming

I am trying to find the mode of a list
Assuming the list is sorted ascending order
Here is my mode function
(define freq
(lambda (l)
(cond ((null? l)l)
((null? (cdr l))l)
((not(equal? (car l) (car(cdr l))))(freq(cdr(delete l (car l)))))
(else (freq (cdr l)))
)))
(freq '(4 4 4 4 5 7 9 9 9)) => should returns 4 but its returning 9 instead

Here's my solution, which is similar to Óscar's solution but centralises the update of the longest/winning result in one place:
(define (longest-run lst)
(let loop ((result #f)
(cur #f)
(count 0)
(longest 0)
(lst lst))
(cond ((> count longest)
(loop cur cur count count lst))
((null? lst) result)
((eqv? (car lst) cur)
(loop result cur (+ count 1) longest (cdr lst)))
(else
(loop result (car lst) 1 longest (cdr lst))))))
I think my solution is shorter, cleaner, and less repetitive, but Óscar's solution has the advantage of updating the variables fewer times: his solution only updates the variables at the end of a run, whereas mine updates the variables whenever the current length is longer than the longest length seen so far.

What's the logic behind your procedure? how do you expect it to find the mode by removing elements from the input list? you should be counting frequencies instead:
(define (mode lst)
(if (null? lst)
#f ; edge case: an empty list doesn't have a mode
(let loop ((lst lst) ; list to traverse
(current (car lst)) ; current element in sequence
(counter 0) ; number of times current element appears
(max-current (car lst)) ; the mode
(max-counter 0)) ; number of times the mode appears
(cond ((null? lst) ; the list is finished
(if (> counter max-counter) current max-current))
((= (car lst) current) ; current element equal to previous
(loop (cdr lst) ; add 1 to counter and keep iterating
current
(add1 counter)
max-current
max-counter))
(else ; found a different element, a new sequence starts
(loop (cdr lst)
(car lst) ; update current element
1
(if (> counter max-counter) current max-current)
(max counter max-counter)))))))
It works by keeping track of how many times each element appears, returning the element that appears most frequently - because by definition the mode is the value that appears most often in a set of data. We take advantage of the fact that the input list is sorted, because we know that a new sequence of repeated elements starts when the current element is different from the previous one we encountered.

Related

Racket: Compare elements in list recursively

This function is supposed to take a list (full of strings or ints, which is why it starts with that 'if' statement) and check to see if it is in ascending order.
I haven't been able to figure out how to keep it from crashing, as on the last recursive call, the 'cadr' has nothing to pull from, as the 'car' is the final element.
(define (my-sorted? lst)
(if (number? (car lst))
(if (< (car lst) (cadr lst))
(my-sorted? (rest lst))
#f)
#f)
)
I know that the sorted function exists, but I need to implement this function recursively.
Thanks for any help.
The two most basic lists that you should try are:
(my-sorted? '()) ; ==> #t (empty list is always sorted)
(my-sorted? '(1)) ; ==> #t (one element list is always sorted)
Your current code just does car and cadr on its argument so it will fail at different levels with these two tests.
The there is how to compare a number and something which is not a number. < expects both arguments to be numbers, but your list can be both strings and numbers. What is smaller of "x" and 7? You cannot do (< 7 "x").
Instead of nesting if you might consider cond which is lisps way of doing if-elseif-else. Basically you can do your code with cond like this:
(cond
((not (number? (car lst))) #f)
((< (car lst) (cadr lst)) (my-sorted? (rest lst))
(else #f))
EDIT
Since the list should either be all elements as string or all as number you simply can just determine the comparison function by looking at the first element and do your recursion with a named let and reuse the one based on the first element.
(define (my-sorted lst)
;; determine what comparison function to use, bind it to greater?
(define greater?
(if (and (pair? lst) (number? (car lst)))
>
string>?))
;; main recursive loop uses that one function
;; this can be done with define + call as well
(let loop ((lst lst))
(cond ((or (null? lst) (null? (cdr lst))) ...)
((greater? (car lst) (cadr lst)) ...)
(else (loop ...)))))

Scheme run length encoding

The problem is to:
Write a function (encode L) that takes a list of atoms L and run-length encodes the list such that the output is a list of pairs of the form (value length) where the first element is a value and the second is the number of times that value occurs in the list being encoded.
For example:
(encode '(1 1 2 4 4 8 8 8)) ---> '((1 2) (2 1) (4 2) (8 3))
This is the code I have so far:
(define (encode lst)
(cond
((null? lst) '())
(else ((append (list (car lst) (count lst 1))
(encode (cdr lst)))))))
(define (count lst n)
(cond
((null? lst) n)
((equal? (car lst) (car (cdr lst)))
(count (cdr lst) (+ n 1)))
(else (n)))))
So I know this won't work because I can't really think of a way to count the number of a specific atom in a list effectively as I would iterate down the list. Also, Saving the previous (value length) pair before moving on to counting the next unique atom in the list. Basically, my main problem is coming up with a way to keep a count of the amount of atoms I see in the list to create my (value length) pairs.
You need a helper function that has the count as additional argument. You check the first two elements against each other and recurse by increasing the count on the rest if it's a match or by consing a match and resetting count to 1 in the recursive call.
Here is a sketch where you need to implement the <??> parts:
(define (encode lst)
(define (helper lst count)
(cond ((null? lst) <??>)
((null? (cdr lst)) <??>))
((equal? (car lst) (cadr lst)) <??>)
(else (helper <??> <??>))))
(helper lst 1))
;; tests
(encode '()) ; ==> ()
(encode '(1)) ; ==> ((1 1))
(encode '(1 1)) ; ==> ((1 2))
(encode '(1 2 2 3 3 3 3)) ; ==> ((1 1) (2 2) (3 4))
Using a named let expression
This technique of using a recursive helper procedure with state variables is so common in Scheme that there's a special let form which allows you to express the pattern a bit nicer
(define (encode lst)
(let helper ((lst lst) (count 1))
(cond ((null? lst) <??>)
((null? (cdr lst)) <??>))
((equal? (car lst) (cadr lst)) <??>)
(else (helper <??> <??>)))))
Comments on the code in your question: It has excess parentheses..
((append ....)) means call (append ....) then call that result as if it is a function. Since append makes lists that will fail miserably like ERROR: application: expected a function, got a list.
(n) means call n as a function.. Remember + is just a variable, like n. No difference between function and other values in Scheme and when you put an expression like (if (< v 3) + -) it needs to evaluate to a function if you wrap it with parentheses to call it ((if (< v 3) + -) 5 3); ==> 8 or 2

Check for ascending order of a list in Racket

I'm new to racket and trying to write a function that checks if a list is in strictly ascending order.
'( 1 2 3) would return true
'(1 1 2) would return false (repeats)
'(3 2 4) would return false
My code so far is:
Image of code
(define (ascending? 'list)
(if (or (empty? list) (= (length 'list) 1)) true
(if (> first (first (rest list))) false
(ascending? (rest list)))))
I'm trying to call ascending? recursively where my base case is that the list is empty or has only 1 element (then trivially ascending).
I keep getting an error message when I use check-expect that says "application: not a procedure."
I guess you want to implement a procedure from scratch, and Alexander's answer is spot-on. But in true functional programming style, you should try to reuse existing procedures to write the solution. This is what I mean:
(define (ascending? lst)
(apply < lst))
It's shorter, simpler and easier to understand. And it works as expected!
(ascending? '(1 2 3))
=> #t
(ascending? '(1 1 2))
=> #f
Some things to consider when writing functions:
Avoid using built in functions as variable names. For example, list is a built in procedure that returns a newly allocated list, so don't use it as an argument to your function, or as a variable. A common convention/alternative is to use lst as a variable name for lists, so you could have (define (ascending? lst) ...).
Don't quote your variable names. For example, you would have (define lst '(1 2 3 ...)) and not (define 'lst '(1 2 3 ...)).
If you have multiple conditions to test (ie. more than 2), it may be cleaner to use cond rather than nesting multiple if statements.
To fix your implementation of ascending? (after replacing 'list), note on line 3 where you have (> first (first (rest list))). Here you are comparing first with (first (rest list)), but what you really want is to compare (first lst) with (first (rest lst)), so it should be (>= (first lst) (first (rest lst))).
Here is a sample implementation:
(define (ascending? lst)
(cond
[(null? lst) #t]
[(null? (cdr lst)) #t]
[(>= (car lst) (cadr lst)) #f]
[else
(ascending? (cdr lst))]))
or if you want to use first/rest and true/false you can do:
(define (ascending? lst)
(cond
[(empty? lst) true]
[(empty? (rest lst)) true]
[(>= (first lst) (first (rest lst))) false]
[else
(ascending? (rest lst))]))
For example,
> (ascending? '(1 2 3))
#t
> (ascending? '(1 1 2))
#f
> (ascending? '(3 2 4))
#f
If you write down the properties of an ascending list in bullet form;
An ascending list is either
the empty list, or
a one-element list, or
a list where
the first element is smaller than the second element, and
the tail of the list is ascending
you can wind up with a pretty straight translation:
(define (ascending? ls)
(or (null? ls)
(null? (rest ls))
(and (< (first ls) (first (rest ls)))
(ascending? (rest ls)))))
This Scheme solution uses an explicitly recursive named let and memoization:
(define (ascending? xs)
(if (null? xs) #t ; Edge case: empty list
(let asc? ((x (car xs)) ; Named `let`
(xs' (cdr xs)) )
(if (null? xs') #t
(let ((x' (car xs'))) ; Memoization of `(car xs)`
(if (< x x')
(asc? x' (cdr xs')) ; Tail recursion
#f)))))) ; Short-circuit termination
(display
(ascending?
(list 1 1 2) )) ; `#f`

Referencing variables in racket

I'm trying to write a simple procedure for finding the n:th prime but I don't think I understand how to reference variables correctly in racket.
What I want is for the inner procedure sieve-iter to add primes to the list primlst which is in the namespace of sieve but I get an infinite loop. My guess is that primlst within sieve-iter is causing issues.
(define (sieve n) ;; returns the n:th prime (n>0)
(let [(primlst '(2))
(cand 3)]
(define (sieve-iter i lst)
(cond ((null? lst) (and (cons i primlst) (sieve-iter (+ i 2) primlst))) ;;prime
((= (length primlst) n) (car primlst)) ;;end
((= (modulo i (car lst)) 0) (sieve-iter (+ i 2) primlst)) ;;non-prime
(#t (sieve-iter n (cdr lst))))) ;;unclear if prime
(sieve-iter cand primlst)))
Any help is appreciated!
First of all, you shouldn't refer to primlist at all within the sieve-iter function. Instead, you should refer to lst.
Second of all, you appear to be mistaken on the effect of this expression:
(and (cons i primlst) (sieve-iter (+ i 2) primlst))
You seem to be interpreting that as meaning "Add i to the primlist and then start the next iteration."
(cons i primlist) changes nothing. Instead, it creates a new list consisting of primlist with i in front of it and then evaluates to that value. The original primlist (which should have been lst anyway) is left untouched.
Also, and is for Boolean logic, not for stringing commands together. It evaluates each of its subexpressions separately until it finds one that evaluates to #f and then it stops.
You should replace that whole expression with this:
(sieve-iter (+ i 2) (cons i lst))
...which passes the new list created by cons to the next run of sieve-iter.
Your trying to do too much in one function, let prime-iter just worry about the iteration to build up the list of primes. Make another internal function to recurse down the existing primes to test the new candidate.
(define (sieve n) ;; returns the n:th prime (n>0)
(define (sieve-iter i lst remaining)
(cond ;((null? lst) (and (cons i primlst) (sieve-iter (+ i 2) primlst))) ;;should never be null, we are building the list up
((<= remaining 0) (car lst)) ;;checking length every time gets expensive added a variable to the function
((sieve-prime? i lst) ;;if prime add to lst and recurse on next i
(sieve-iter (+ i 2) (cons i lst) (- remaining 1)))
(else
(sieve-iter (+ i 2) lst remaining)))) ; else try next
(define (sieve-prime? i lst)
(cond ((null? lst) #t)
((= 0 (modulo i (car lst))) #f)
(else (sieve-prime? i (cdr lst)))))
(let ((primlst '(2)) ;;you generally don't modify these,
(cand 3)) ;mostly they just bind values to name for convenience or keep from having to re-calculate the same thing more than once
(sieve-iter cand primlst (- n 1))))
You could have used set! to modify primlist where it was before, but the procedure is no longer obviously a pure function.
There is another low-handing optimization possible here, when calling sieve-prime? filter the lst argument to remove values larger than the square root of i.

Scheme sum of list

First off, this is homework, but I am simply looking for a hint or pseudocode on how to do this.
I need to sum all the items in the list, using recursion. However, it needs to return the empty set if it encounters something in the list that is not a number. Here is my attempt:
(DEFINE sum-list
(LAMBDA (lst)
(IF (OR (NULL? lst) (NOT (NUMBER? (CAR lst))))
'()
(+
(CAR lst)
(sum-list (CDR lst))
)
)
)
)
This fails because it can't add the empty set to something else. Normally I would just return 0 if its not a number and keep processing the list.
I suggest you use and return an accumulator for storing the sum; if you find a non-number while traversing the list you can return the empty list immediately, otherwise the recursion continues until the list is exhausted.
Something along these lines (fill in the blanks!):
(define sum-list
(lambda (lst acc)
(cond ((null? lst) ???)
((not (number? (car lst))) ???)
(else (sum-list (cdr lst) ???)))))
(sum-list '(1 2 3 4 5) 0)
> 15
(sum-list '(1 2 x 4 5) 0)
> ()
I'd go for this:
(define (mysum lst)
(let loop ((lst lst) (accum 0))
(cond
((empty? lst) accum)
((not (number? (car lst))) '())
(else (loop (cdr lst) (+ accum (car lst)))))))
Your issue is that you need to use cond, not if - there are three possible branches that you need to consider. The first is if you run into a non-number, the second is when you run into the end of the list, and the third is when you need to recurse to the next element of the list. The first issue is that you are combining the non-number case and the empty-list case, which need to return different values. The recursive case is mostly correct, but you will have to check the return value, since the recursive call can return an empty list.
Because I'm not smart enough to figure out how to do this in one function, let's be painfully explicit:
#lang racket
; This checks the entire list for numericness
(define is-numeric-list?
(lambda (lst)
(cond
((null? lst) true)
((not (number? (car lst))) false)
(else (is-numeric-list? (cdr lst))))))
; This naively sums the list, and will fail if there are problems
(define sum-list-naive
(lambda (lst)
(cond
((null? lst) 0)
(else (+ (car lst) (sum-list-naive (cdr lst)))))))
; This is a smarter sum-list that first checks numericness, and then
; calls the naive version. Note that this is inefficient, because the
; entire list is traversed twice: once for the check, and a second time
; for the sum. Oscar's accumulator version is better!
(define sum-list
(lambda (lst)
(cond
((is-numeric-list? lst) (sum-list-naive lst))
(else '()))))
(is-numeric-list? '(1 2 3 4 5))
(is-numeric-list? '(1 2 x 4 5))
(sum-list '(1 2 3 4 5))
(sum-list '(1 2 x 4 5))
Output:
Welcome to DrRacket, version 5.2 [3m].
Language: racket; memory limit: 128 MB.
#t
#f
15
'()
>
I suspect your homework is expecting something more academic though.
Try making a "is-any-nonnumeric" function (using recursion); then you just (or (is-any-numeric list) (sum list)) tomfoolery.

Resources