Drracket: Create a function that will return a sorted list given a comparer using bubble sort - sorting

This is what I have to sort strings:
;create a function that checks if a list of strings is sorted
(define (stringCmpr l)
(if (<= (length l) 1)
true
(and (string<=? (car l) (cadr l))(stringCmpr (cdr l))
)
)
)
;Create a funciton that checks if a list of numbers is sorted
(define (numCmpr l)
(if (<= (length l) 1)
true
(and (<= (car l) (cadr l)) (numCmpr (cdr l))
)
)
)
;create function that checks whether a list containes numbers of
strings checks if the list is sorted
(define (is-sorted? l)
(if (number? (car l))
(numCmpr l)
(stringCmpr l)
)
)
(define (bubble-pass lst)
(cond
((empty? lst) lst)
((= (length lst) 1) lst)
((and (= (length lst) 2) (string>? (first lst) (second lst)))
(list
(second lst) (first lst)))
((and (= (length lst) 2) (string<? (first lst) (second lst)))
lst)
((string>? (first lst) (second lst))
(append
(list (second lst))
(bubble-pass (append (list (first lst)) (rest (rest lst))))
)
)
(else
(append (list (first lst) (second lst)) (bubble-pass (rest
(rest lst))))
)
)
)
(define (string-bubble-sort lst)
(if (is-sorted? lst)
lst
(string-bubble-sort (bubble-pass last))
)
)
This works for sorting strings in order from A-Z
This is what I have so far for the general sort (func represents the comparer: <, > =, string<?, etc):
;create a function that checks if a list of strings is sorted
(define (gen-stringCmpr l func)
(if (<= (length l) 1)
true
(and (func (car l) (cadr l))(gen-stringCmpr (cdr l) func)
)
)
)
;Create a funciton that checks if a list of numbers is sorted
(define (gen-numCmpr l func)
(if (<= (length l) 1)
true
(and (func (car l) (cadr l)) (gen-numCmpr (cdr l) func)
)
)
)
;create funciton that checks whether a list contains numbers or
strings checks if the list is sorted
(define (general-sorted? l func)
(if (number? (car l))
(gen-numCmpr l func)
(gen-stringCmpr l func)
)
)
; Purpose: Create a function that bubble sorts a list given a
; comparison function
;Signature:
; list function-> list
;Examples:
(check-expect (general-bubble-sort (list "B" "A" "C") string<?) (list
"A" "B" "C"))
(check-expect (general-bubble-sort (list "B" "A" "C") string>?) (list
"C" "B" "A"))
(check-expect (general-bubble-sort (list 6 4 5) <) (list 4 5 6))
(check-expect (general-bubble-sort (list 2 3 1) >) (list 3 2 1))
Stub:
(define (general-bubble-sort lst func) '( "spinach")
Template:
Code:
(define (general-bubble-pass lst func)
(cond
((empty? lst) last)
((= (length lst) 1) last)
((and (= (length lst) 2) (equal? (func (first lst) (second lst))
false)) (list (second lst) (first lst)))
((and (= (length lst) 2) (func (first lst) (second lst))) last)
((equal? (func (first lst) (second lst)) false)
(append
(list (second last))
(general-bubble-pass (append (list (first lst)) (rest (rest
lst))) func)
)
)
(else
(append (list (first lst) (second lst)) (general-bubble-pass
(rest (rest lst)) func))
)
)
)
(define (general-bubble-sort lst func)
(if (general-sorted? lst func)
lst
(general-bubble-sort (general-bubble-pass lst func) func)
)
)

You aren't properly using your abstractions here because of overly permissive signatures. Technically you want your final bubble sort to work like this:
; general-bubble-sort: (X) [List-of X] [X X -> Boolean] -> [List-of X]
By constraining the types of what we take in and telling users how they should use it, we eliminate the checking we need to do in general-sorted?. We just know that we have to pass the correct function to it, otherwise it is the users fault for not passing the correct function. You can also abstract more of your code between your two functions. Like this:
(define (general-sorted? l func)
(or (<= (length l) 1) (and (func (car l) (cadr l)) (general-sorted? (cdr l)))))
Your second function has a lot going on in it, lets combine some of the cases and also not use (equal? x boolean). That is bad practice. Instead we should use a boolean expression to get us true when appropriate. We should also make use of accumulators here as it clearly says what piece of data we are keeping track of as we are recurring down:
(define (general-bubble-pass lst func)
(local [(define (general-bubble-pass-acc lst bubble)
(cond
[(empty? lst) (list bubble)]
[(not (func (first lst) bubble)) (cons bubble (general-bubble-pass-acc (rest lst) (first lst)))]
[else (cons (first lst) (general-bubble-pass-acc (rest lst) bubble))]))]
(if (<= (length lst) 1) lst (general-bubble-pass-acc (rest lst) (first lst)))))
Your final bubble sort function doesn't change.

Related

How do I get this scheme to work properly? what am i doing wrong?

(define first car)
(define rest cdr)
(define (ins lst ele)
(if (not (mem lst ele)) (append lst (list ele)) lst)
)
when I call the function (ins 5'(2 10 -3)) it's supposed to add the 5 into the list and should return (5 2 10 -3) but I can't figure out what is going on. Can someone guide me?
I keep getting this error
mem: undefined;
cannot reference an identifier before its definition
Don't you mean:
(define first car)
(define rest cdr)
(define (ins lst ele)
(if (not (member? ele lst)) (append lst (list ele)) lst))
Or you define mem yourself
(define (mem lst ele)
(cond ((null? lst) #f)
((equal? ele (car lst)) #t)
(else (mem (cdr lst) ele))))
With extra test:
(define (mem lst ele (test equal?))
(cond ((null? lst) #f)
((test ele (car lst)) #t)
(else (mem (cdr lst) ele test))))
And tail call recursion with recursive search within lst:
(define (mem* lst ele (test equal?) (acc #f))
(cond ((null? lst) acc)
((list? (car lst)) (mem* (cdr lst) ele test (or acc (mem* (car lst) ele test))))
((test ele (car lst)) #t)
(else (mem* (cdr lst) ele test acc))))
And after one of those you add:
(define first car)
(define rest cdr)
(define (ins lst ele)
(if (not (mem ele lst)) (append lst (list ele)) lst))

SCHEME Mutable Functions

I've been self-teaching myself Scheme R5RS for the past few months and have just started learning about mutable functions. I've did a couple of functions like this, but seem to find my mistake for this one.
(define (lst-functions)
(let ((lst '()))
(define (sum lst)
(cond ((null? lst) 0)
(else
(+ (car lst) (sum (cdr lst))))))
(define (length? lst)
(cond ((null? lst) 0)
(else
(+ 1 (length? (cdr lst))))))
(define (average)
(/ (sum lst) (length? lst)))
(define (insert x)
(set! lst (cons x lst)))
(lambda (function)
(cond ((eq? function 'sum) sum)
((eq? function 'length) length?)
((eq? function 'average) average)
((eq? function 'insert) insert)
(else
'undefined)))))
(define func (lst-functions))
((func 'insert) 2)
((func 'average))
You're not declaring the lst parameter in the procedures that use it, but you're passing it when invoking them. I marked the lines that were modified, try this:
(define (lst-functions)
(let ((lst '()))
(define (sum lst) ; modified
(cond ((null? lst) 0)
(else
(+ (car lst) (sum (cdr lst))))))
(define (length? lst) ; modified
(cond ((null? lst) 0)
(else
(+ 1 (length? (cdr lst))))))
(define (average)
(/ (sum lst) (length? lst)))
(define (insert x)
(set! lst (cons x lst)))
(lambda (function)
(cond ((eq? function 'sum) (lambda () (sum lst))) ; modified
((eq? function 'length) (lambda () (length? lst))) ; modified
((eq? function 'average) average)
((eq? function 'insert) insert)
(else
'undefined)))))
Now it works as expected:
(define func (lst-functions))
((func 'insert) 2)
((func 'average))
=> 2
((func 'sum))
=> 2
((func 'length))
=> 1
Some of your functions are recursive but defined without argument. Thus (sum (cdr lst)) shouldn't work since sum uses lst. You could do it by defining a helper:
(define (sum-rec lst)
(if (null? lst)
0
(+ (car lst) (sum-rec (cdr lst)))))
Or perhaps with an accumulator:
(define (sum-iter lst acc)
(if (null? lst)
acc
(sum-iter (cdr lst) (+ (car lst) acc)))
Your sum would of course use it passing the lst:
(define (sum)
(sum-iter lst 0))
Or you can just have the driver partial apply them like this:
(lambda (function)
(cond ((eq? function 'sum) (lambda () (sum-iter lst))
...))
A side note. length? is a strangely named function. A question mark in the end of a name is usually reserved for functions that return a true or a false value and this clearly returns a number.

Scheme - How to find the median using user defined sort and average functions?

I'm new to Scheme, and I've hit a wall. I have my sort and average functions, and I'm trying to change a median function I found on this site. However, no matter what I try, I keep getting errors where I have more than one expression in the median function, or when I try to use sort in the median function it's "undefined".
(define (sort1 L)
(if (or (null? L) (<= (length L) 1)) L
(let loop ((l null) (r null)
(pivot (car L)) (rest (cdr L)))
(if (null? rest)
(append (append (sort1 l) (list pivot)) (sort1 r))
(if (<= (car rest) pivot)
(loop (append l (list (car rest))) r pivot (cdr rest))
(loop l (append r (list (car rest))) pivot (cdr rest)))))))
(define (avg lst)
(let loop ((count 0) (sum 0) (args lst))
(if (not (null? args))
(loop (add1 count) (+ sum (car args)) (cdr args))
(/ sum count))))
(define (median L)
(if (null? L) (error "The list is empty")
(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)))))))
I'm trying to edit the median function to first sort the list, and if there are an even number of elements, I need to take the average of the list, and use the element closest to the average.
Any help would be appreciated, thank you in advance.
Like I said in a comment, what you want isn't a let, it's function composition.
Your current median function is this:
(define (median L)
(if (null? L)
(error "The list is empty")
(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)))))))
But as Oscar Lopez pointed out, this doesn't properly compute the median. However, it does some of the work, so keep it. Rename it to median-helper or something.
(define (median-helper L)
(if (null? L)
(error "The list is empty")
(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)))))))
Then you can use function composition to define the "real" median function:
(define (median lst)
(median-helper (sort1 lst)))
This returns the middle element for odd-length lists, and the middle-two elements for even length lists. If this is want you wanted, great. If not, then you can fix median-helper by returning the average in the second case of the cond. So instead of (list (car L1) (cadr L1)) there, you would have (avg (list (car L1) (cadr L1))).
;; median-helper : (Listof Number) -> Number
(define (median-helper L)
(if (null? L)
(error "The list is empty")
(let loop ((L1 L) (L2 L))
(cond ((null? (cdr L2)) (car L1))
((null? (cddr L2)) (avg (list (car L1) (cadr L1))))
(else (loop (cdr L1) (cddr L2)))))))
;; median : (Listof Number) -> Number
(define (median lst)
(median-helper (sort1 lst)))
I think you're misunderstanding the definition of a median. A very simple (if not particularly efficient) implementation follows:
(define (my-sort L)
(sort L <))
(define (average x y)
(exact->inexact (/ (+ x y) 2)))
(define (median L)
(if (null? L)
(error "The list is empty")
(let* ((n (length L))
(sorted (my-sort L))
(half (quotient n 2)))
(if (odd? n)
(list-ref sorted half)
(average (list-ref sorted half)
(list-ref sorted (sub1 half)))))))
It works as defined:
(median '())
=> The list is empty
(median '(3 2 1 5 4))
=> 3
(median '(6 4 3 1 2 5))
=> 3.5

List order after duplicate filtering

I'm trying to teach myself functional language thinking and have written a procedure that takes a list and returns a list with duplicates filtered out. This works, but the output list is sorted in the order in which the last instance of each duplicate item is found in the input list.
(define (inlist L n)
(cond
((null? L) #f)
((= (car L) n) #t)
(else (inlist (cdr L) n))
))
(define (uniquelist L)
(cond
((null? L) '())
((= 1 (length L)) L)
((inlist (cdr L) (car L)) (uniquelist (cdr L)))
(else (cons (car L) (uniquelist (cdr L))))
))
So..
(uniquelist '(1 1 2 3)) => (1 2 3)
...but...
(uniquelist '(1 2 3 1)) => (2 3 1)
Is there a simple alternative that maintains the order of the first instance of each duplicate?
The best way to solve this problem would be to use Racket's built-in remove-duplicates procedure. But of course, you want to implement the solution from scratch. Here's a way using idiomatic Racket, and notice that we can use member (another built-in function) in place of inlist:
(define (uniquelist L)
(let loop ([lst (reverse L)] [acc empty])
(cond [(empty? lst)
acc]
[(member (first lst) (rest lst))
(loop (rest lst) acc)]
[else
(loop (rest lst) (cons (first lst) acc))])))
Or we can write the same procedure using standard Scheme, as shown in SICP:
(define (uniquelist L)
(let loop ((lst (reverse L)) (acc '()))
(cond ((null? lst)
acc)
((member (car lst) (cdr lst))
(loop (cdr lst) acc))
(else
(loop (cdr lst) (cons (car lst) acc))))))
The above makes use of a named let for iteration, and shows how to write a tail-recursive implementation. It works as expected:
(uniquelist '(1 1 2 3))
=> '(1 2 3)
(uniquelist '(1 2 3 1))
=> '(1 2 3)

Removing null elements from the scheme list

(define filter-in
(lambda (predicate list)
(let((f
(lambda (l)
(filter-in-sexpr predicate l))))
(map f list))))
(define filter-in-aux
(lambda (pred lst)
(if (null? lst) '()
(cons (filter-in-sexpr pred (car lst))
(filter-in-aux pred (cdr lst))))))
(define filter-in-sexpr
(lambda (pred sexpr)
(if (equal? (pred sexpr) #t)
sexpr
'())))
Calling (filter-in number? ’(a 2 (1 3) b 7)) produces ( () 2 () () 7).
How I can skip null elements from the generated list to get final outcome of (2 7) ?
The problem is that you're mapping filter-in-sxpr over the list. You can either run another filter pass to remove the nulls, or use a modified filter-in-aux like this:
(define filter-in-aux
(lambda (pred lst)
(if (null? lst) '()
(let ((h (filter-in-sexpr pred (car lst)))
(t (filter-in-aux pred (cdr lst))))
(if (null? h) t
(cons h t))))))

Resources