Rotating a list to the right in scheme - scheme

if this is rotating a list to the left:
(define (rotate-left l)
(if (null? l)
'()
(append (cdr l) (cons(car l) '()))))
How would I rotate a list to the right?

If you're ok with writing a helper function to find the last element, it's pretty easy to do a recursive implementation:
(define rotate-right
(lambda (lis full)
(if (null? (cdr lis))
(cons (car lis) (get-all-but-last full))
(rotate-right (cdr lis) full))))
(define get-all-but-last
(lambda (lis)
(if (null? (cdr lis))
'()
(cons (car lis) (get-all-but-last (cdr lis))))))

Here is a short non-recursive solution:
(define (rotate-right l)
(let ((rev (reverse l)))
(cons (car rev) (reverse (cdr rev)))))
And here is a iterative solution:
(define (rotate-right l)
(let iter ((remain l)
(output '()))
(if (null? (cdr remain))
(cons (car remain) (reverse output))
(iter (cdr remain) (cons (car remain) output)))))
(rotate-right '(1 2 3 4 5)) ;==> (5 1 2 3 4)

Related

Returning two parts of a list as a pair

In my program, I am supposed to write a function where it splits a list into even and odd. The problem is that the output/syntax is incorrect. I am getting ((1 3) (2 4)) when testing out the example (split '(1 2 3 4)). The output needs to look like ((1 3) 2 4)
Here is my code:
(define (split l)
(define (odd l)
(if (null? l) '()
(if (null? (cdr l)) (list (car l))
(cons (car l) (odd (cddr l))))))
(define (even l)
(if (null? l) '()
(if (null? (cdr l)) '()
(cons (cadr l) (even (cddr l))))))
(cons (odd l) (cons (even l) '())))
(even l) is already a list. You don't need to wrap it in an extra cons.
The code below should work.
(define (split l)
(define (odd l)
(if (null? l) '()
(if (null? (cdr l)) (list (car l))
(cons (car l) (odd (cddr l))))))
(define (even l)
(if (null? l) '()
(if (null? (cdr l)) '()
(cons (cadr l) (even (cddr l))))))
(cons (odd l) (even l)))

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

Sort function with customizable comparision function

After writing:
(define (sort-asc l)
(cond ((eq? l '()) '())
((eq? (cdr l) '()) (list (car l)))
((< (car l) (cadr l)) (cons (car l) (sort-asc (cdr l)) ))
(else (cons (cadr l) (sort-asc (cons (car l) (cddr l)) )))))
How do you write a function that can additionally take a comparison function as a parameter?
Tried:
(define (sort-f l f)
(cond ((eq? l '()) '())
((eq? (cdr l) '()) (list (car l)))
((lambda ()(f (car l) (cadr l))) (cons (car l) (sort-f (cdr l) f)))
(else (cons (cadr l) (sort-f (cons (car l) (cddr l)) f)))))
But (sort-f '(4 3 8 2 5) <) returns the same list.
p.s. Is there any way to make this code look more elegant by somehow rewriting of all the car's, cadr's and cdr's?
Your third cond branch condition should be (f (car l) (cadr l)), not (lambda () ...). The lambda expression returns a procedure (which is not invoked), and since all procedures are truthy, the fourth (else) branch is never reached.
That is,
((lambda ()(f (car l) (cadr l))) (cons (car l) (sort-f (cdr l) f)))
should be
((f (car l) (cadr l)) (cons (car l) (sort-f (cdr l) f)))

Removing Duplicates from a list as well as the elements themselves- Racket, Scheme

(define (remove-duplicates l)
(cond ((empty? l)
'())
((member (first l) (rest l))
(remove-duplicates (rest l)))
(else
(cons (first l) (remove-duplicates (rest l))))))
This code has this result.
> (remove-duplicates (list 1 1 2 2 3 4))
(list 1 2 3 4)
Without using filter, I would like the result to be
(remove-duplicates (list 1 1 2 2 3 4)) gives
(list 3 4)
Help would be deeply appreciated. Thanks in advance.
You could use a helper function:
(define helper
(lambda (lst collector dup)
(cond [(null? lst) collector]
[(memq (car lst) (cdr lst)) (helper (cdr lst) collector (cons (car lst) dup))]
[(memq (car lst) dup) (helper (cdr lst) collector dup)]
[else
(helper (cdr lst) (cons (car lst) collector) dup)])))
Maintain two lst, collector for all unique element, and dup for duplicated elements.
(define remove-dup
(lambda (lst)
(reverse (helper lst '() '()))))

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)

Resources