Returning two parts of a list as a pair - scheme

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)))

Related

Create palindrom function without append function in output in scheme

i am trying to create palyndrom function which is doing palyndrom from input string. Something like this: (palindrome '(1 2 3 4)) ==> (1 2 3 4 3 2 1).
I have created this code below but it is returning me (palindrome '(1 2 3 4)) ==> (1 (2 (3 (4) 3) 2) 1)
My code is below. Task is to NOT use append or reverse.
(define (palindrome l)
(cond
((null? (cdr l)) (list (car l)))
((list (car l) (palindrome (cdr l)) (car l)))))
Thanks for help.
As in the comment of Sylwester, you can do your own version of append or reverse. Here is an example in which only the append function (called concatenate) is defined.
(define (palindrome l)
(define (concatenate l1 l2)
(if (null? l1)
l2
(cons (car l1) (concatenate (cdr l1) l2))))
(define (p l)
(cond ((null? l) '())
((null? (cdr l)) l)
(else (cons (car l) (concatenate (p (cdr l)) (list (car l)))))))
(p l))
(palindrome '(1 2 3 4))
'(1 2 3 4 3 2 1)
Here instead is a tail recursive version:
(define (palindrome l)
(define (concatenate l1 l2)
(if (null? l1)
l2
(cons (car l1) (concatenate (cdr l1) l2))))
(define (p l prefix suffix)
(cond ((null? l) (concatenate prefix suffix))
((null? (cdr l)) (concatenate prefix (cons (car l) suffix)))
(else (p (cdr l) (concatenate prefix (list (car l))) (cons (car l) suffix)))))
(p l '() '()))

Rotating a list to the right in 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)

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)))

Scheme: what wrong with that code?

I wrote this code to remove duplicate and it is work. But when i add the option for the equal function there are problems. what can i do??
thank you!!
(define (remove-dups ls eq)
(if (null? ls) '()
(cons (car ls) (remove-dups (deepRemove (car ls) (cdr ls) eq)))))
(define (deepRemove n L eq)
(if (null? L) '()
(if (list? (car L))
(cons (deepRemove n (car L) eq) (deepRemove n (cdr L) eq))
(if (eq? n (car L))(deepRemove n (cdr L) eq)
(cons (car L)(deepRemove n (cdr L) eq))))))
There are at least two errors with your code. First, you're passing the wrong number of arguments to remove-dups. Second, you're not actually using the eq parameter in deepRemove. Also, you should use cond instead of nesting ifs, but that's more a matter of style. Try this:
(define (remove-dups ls eq)
(if (null? ls)
'()
(cons (car ls)
(remove-dups (deepRemove (car ls) (cdr ls) eq) eq)))) ; fixed
(define (deepRemove n L eq)
(if (null? L)
'()
(if (list? (car L))
(cons (deepRemove n (car L) eq)
(deepRemove n (cdr L) eq))
(if (eq n (car L)) ; fixed
(deepRemove n (cdr L) eq)
(cons (car L)
(deepRemove n (cdr L) eq))))))
The above will work as long as you pass an appropriate eq procedure that takes into consideration all the possible values that need to be compared, be careful with that.

Resources