How to sort disorder list of numbers in scheme - scheme

What it the proper way to sort a list with values in Scheme? For example I have the values which are not ordered:
x1, x5, x32 .... xn
or
3, 4, 1, 3, 4, .. 9
First I want to for them by increase number and display them in this order:
x1, xn, x2, xn-1
or
1, 6, 2, 5, 3, 4
Any help will be valuable.

This is the same question you posted before, but with a small twist. As I told you in the comments of my answer, you just have to sort the list before rearranging it. Here's a Racket solution:
(define (interleave l1 l2)
(cond ((empty? l1) l2)
((empty? l2) l1)
(else (cons (first l1)
(interleave l2 (rest l1))))))
(define (zippy lst)
(let-values (((head tail) (split-at
(sort lst <) ; this is the new part
(quotient (length lst) 2))))
(interleave head (reverse tail))))
It works as expected:
(zippy '(4 2 6 3 5 1))
=> '(1 6 2 5 3 4)

This R6RS solution does what Chris Jester-Young proposes and it really is how to do it the bad way. BTW Chris' and Óscar's solutions on the same question without sorting is superior to this zippy procedure.
#!r6rs
(import (rnrs base)
(rnrs sorting)) ; list-sort
(define (zippy lis)
(let loop ((count-down (- (length lis) 1))
(count-up 0))
(cond ((> count-up count-down) '())
((= count-up count-down) (cons (list-ref lis count-down) '()))
(else (cons (list-ref lis count-down)
(cons (list-ref lis count-up)
(loop (- count-down 1)
(+ count-up 1))))))))
(define (sort-rearrange lis)
(zippy (list-sort < lis)))

Here is a simple, tail-recursive approach that uses a 'slow/fast' technique to stop the recursion when half the list is traversed:
(define (interleave l)
(let ((l (list-sort < l)))
(let merging ((slow l) (fast l) (revl (reverse l)) (rslt '()))
(cond ((null? fast)
(reverse rslt))
((null? (cdr fast))
(reverse (cons (car slow) rslt)))
(else
(merging (cdr slow) (cddr fast) (cdr revl)
(cons (car revl) (cons (car slow) rslt))))))))

So, you don't mind slow and just want a selection-based approach, eh? Here we go....
First, we define a select1 function that gets the minimum (or maximum) element, followed by all the other elements. For linked lists, this is probably the simplest approach, easier than trying to implement (say) quickselect.
(define (select1 lst cmp?)
(let loop ((seen '())
(rest lst)
(ext #f)
(extseen '()))
(cond ((null? rest)
(cons (car ext) (append-reverse (cdr extseen) (cdr ext))))
((or (not ext) (cmp? (car rest) (car ext)))
(let ((newseen (cons (car rest) seen)))
(loop newseen (cdr rest) rest newseen)))
(else
(loop (cons (car rest) seen) (cdr rest) ext extseen)))))
Now actually do the interweaving:
(define (zippy lst)
(let recur ((lst lst)
(left? #t))
(if (null? lst)
'()
(let ((selected (select1 lst (if left? < >))))
(cons (car selected) (recur (cdr selected) (not left?)))))))
This approach is O(n²), whereas the sort-and-interleave approach recommended by everybody else here is O(n log n).

Related

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

How do I write a function in DrRacket ISL/Lambda that moves occurrences of certain items to the end of the list?

I'm trying to learn how to do this, and I know it involves stacks, but I can't wrap my head around it unless I see a function in action. We've been given this example of a function to create and I need some help. Here it is:
;leafpile takes a list and returns the result of pushing all
;occurrences of the symbol 'leaf to the end of the list
> (leafpile '(rock grass leaf leaf acorn leaf))
(list 'rock 'grass 'acorn 'leaf 'leaf 'leaf)
We can use a helper function but the function needs to be written in a way to minimize recursive passes
update (heres what I got so far)
(define (leafpile/help ls pile)
(local
[
(define (helper 2ls leafpile)
(cond
[(empty? 2ls) (filter ls 'leaf)]
[(equal? (first 2ls) 'leaf)
(cons (first 2ls) (helper (rest 2ls) leafpile))]
[else (helper (rest 2ls) leafpile)]))]
(helper ls pile)))
OK snow I have this:
(define (helper lsh)
(cond
[(empty? lsh) '()]
[(not(equal? (first lsh) 'leaf))
(cons (first lsh) (helper (rest lsh)))]
[else (helper (rest lsh))]))
(define (count-leaf ls)
(cond
[(empty? ls) 0]
[(not (equal? 'leaf (first ls))) (count-leaf (rest ls))]
[else (add1 (count-leaf (rest ls)))]))
(define (leafpile ls)
(append (helper ls) (make-list (count-leaf ls) 'leaf)))
but I need it in one simple function with the least recursive passes possible.
Here is the solution I came up with:
(define (leafpile lst)
(for/fold ([pile (filter (lambda (leaf?) (not (equal? leaf? 'leaf))) lst)])
([i (build-list (for/fold ([leaves 0])
([leaf? lst])
(if (equal? leaf? 'leaf)
(add1 leaves)
leaves)) values)])
(append pile '(leaf))))
How it works:
The main for/fold loop iterates over a list with a length of the number of leaves there are, and the 'collection value' is a list of all the elements in lst that aren't the symbol 'leaf (achieved by filter).
Sample input/output:
> (leaf-pile '(rock grass leaf leaf acorn leaf))
'(rock grass acorn leaf leaf leaf)
Really simple way to do this:
(define (leaf? v)
(eq? v 'leaf))
(define (leafpile lst)
(append (filter (compose not leaf?) lst)
(filter leaf? lst)))
It really doesn't need to be more to it unless you experience performance issues and I usually don't for small lists. I tend to think of lists with fewer than a million elements as small. The obvious recursive one that might not be faster:
(define (leafpile lst)
(local [(define (leafpile lst n) ; screaming for a named let here!
(cond
((null? lst) (make-list n 'leaf))
((leaf? (car lst)) (leafpile (cdr lst) (add1 n)))
(else (cons (car lst) (leafpile (cdr lst) n)))))]
(leafpile lst 0)))
A tail recursive one that accumulates non leaf values, counts leaf values and uses srfi/1 append-reverse! to produce the end result:
(require srfi/1)
(define (leafpile lst)
(local [(define (leafpile lst acc n) ; I'm still screaming
(cond
((null? lst) (append-reverse! acc (make-list n 'leaf)))
((leaf? (car lst)) (leafpile (cdr lst) acc (add1 n)))
(else (leafpile (cdr lst) (cons (car lst) acc) n))))]
(leafpile lst '() 0)))

Same-parity in Scheme

I am trying to solve the exercise 2.20 from SICP book. The exercise -
Write a procedure same-parity that takes one or more integers and returns a list of
all the arguments that have the same even-odd parity as the first argument. For example,
(same-parity 1 2 3 4 5 6 7)
(1 3 5 7)
(same-parity 2 3 4 5 6 7)
(2 4 6)
My code -
(define same-parity (lambda (int . l)
(define iter-even (lambda (l2 rl)
(cons ((null? l2) rl)
((even? (car l2))
(iter-even (cdr l2) (append rl (car l2))))
(else (iter-even (cdr l2) rl)))))
(define iter-odd (lambda (l2 rl)
(cons ((null? l2) rl)
((odd? (car l2))
(iter-odd (cdr l2) (append rl (car l2))))
(else (iter-odd (cdr l2) rl)))))
(if (even? int) (iter-even l (list int))
(iter-odd l (list int)))))
For some reason I am getting an error saying "The object (), passed as the first argument to cdr, is not the correct type". I tried to solve this for more than two hours, but I cant find any reason why it fails like that. Thanks for hlep.
Try this:
(define same-parity
(lambda (int . l)
(define iter-even
(lambda (l2 rl)
(cond ((null? l2) rl)
((even? (car l2))
(iter-even (cdr l2) (append rl (list (car l2)))))
(else (iter-even (cdr l2) rl)))))
(define iter-odd
(lambda (l2 rl)
(cond ((null? l2) rl)
((odd? (car l2))
(iter-odd (cdr l2) (append rl (list (car l2)))))
(else (iter-odd (cdr l2) rl)))))
(if (even? int)
(iter-even l (list int))
(iter-odd l (list int)))))
Explanation:
You are using cons instead of cond for the different conditions
in the part where append is called, the second argument must be a proper list (meaning: null-terminated) - but it is a cons-pair in your code. This was causing the error, the solution is to simply put the second element inside a list before appending it.
I must say, using append to build an output list is frowned upon. You should try to write the recursion in such a way that cons is used for creating the new list, this is more efficient, too.
Some final words - as you're about to discover in the next section of SICP, this problem is a perfect fit for using filter - a more idiomatic solution would be:
(define (same-parity head . tail)
(if (even? head)
(filter even? (cons head tail))
(filter odd? (cons head tail))))
First, I check the first element in the list. If it is even, I call the procedure that forms a list out of only the even elements. Else, I call the procedure that forms a list out of odd elements.
Here's my code
(define (parity-helper-even B)(cond
((= 1 (length B)) (cond
((even? (car B)) B)
(else '())
))
(else (cond
((even? (car B)) (append (list (car B)) (parity-helper-even (cdr B))))
(else (parity-helper-even(cdr B)))
))))
(define (parity-helper-odd B)(cond
((= 1 (length B)) (cond
((odd? (car B)) B)
(else '())
))
(else (cond
((odd? (car B)) (append (list (car B)) (parity-helper-odd (cdr B))))
(else (parity-helper-odd (cdr B)))
))))
(define (same-parity first . L) (cond
((even? first) (parity-helper-even (append (list first) L)))
(else (parity-helper-odd (append (list first) L)))))
(same-parity 1 2 3 4 5 6 7)
;Output (1 3 5 7)
While you are traversing the list, you might as well just split it into even and odd parities. As the last step, choose the one you want.
(define (parities args)
(let looking ((args args) (even '()) (odd '()))
(if (null? args)
(values even odd)
(let ((head (car args)))
(if (even? head)
(looking (cdr args) (cons head even) odd)
(looking (cdr args) even (cons head odd)))))))
(define (same-parity head . rest)
(let-values ((even odd) (parities (cons head rest)))
(if (even? head)
even
odd)))
Except for homework assignments, if you are going to look for one then you are likely to need the other. Said another way, you'd find yourself using parities more frequently in practice.
You could simply filter elements by parity of first element:
(define (same-parity x . y)
(define (iter z filter-by)
(cond ((null? z) z)
((filter-by (car z))
(cons (car z) (iter (cdr z) filter-by)))
(else (iter (cdr z) filter-by))))
(iter (cons x y) (if (even? x) even? odd?)))
And try:
(same-parity 1 2 3 4 5 6 7)
(same-parity 2 3 4 5 6 7)

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)

How to improve this mergesort in scheme?

I am a C++ programmer, I wrote this code to see if I can think functionally :)
Any hints to improve it ?
(define (append listOne listTwo)
(cond
((null? listOne) listTwo)
(else (cons (car listOne) (append (cdr listOne) listTwo)))))
(define (merge listOne listTwo)
(cond
((null? listOne) listTwo)
((null? listTwo) listOne)
((< (car listOne) (car listTwo))
(append (cons (car listOne) '())
(merge (cdr listOne) listTwo)))
((= (car listOne) (car listTwo))
(append (cons (car listOne) '())
(merge (cdr listOne) listTwo)))
(else (append (cons (car listTwo) '())
(merge listOne (cdr listTwo))))))
(define (mergesort lis)
(cond
((null? lis) '())
((null? (cdr lis)) lis)
(else (merge (cons (car lis) '())
(mergesort (cdr lis))))))
(mergesort '(99 77 88 66 44 55 33 11 22 0))
There's only one small improvement that I see:
(append (cons (car listTwo) '())
(merge listOne (cdr listTwo))))
can everywhere be simplified to
(cons (car listTwo)
(merge listOne (cdr listTwo)))
I think you were thinking of something like (in Python-esque syntax):
[car(listTwo)] + merge(listOne, cdr(listTwo))
But cons adds an item directly to the front of a list, like a functional push, so it's like the following code:
push(car(listTwo), merge(listOne, cdr(listTwo)))
Ultimately the extra append only results in double cons cell allocation for each item, so it's not a big deal.
Also, I think you might get better performance if you made mergesort fancier so that it maintains the list length and sorts both halves of the list at each step. This is probably not appropriate for a learning example like this, though.
Something like:
(define (mergesort l)
(let sort-loop ((l l) (len (length l)))
(cond
((null? l) '())
((null? (cdr l)) l)
(else (merge (sort-loop (take (/ len 2) l) (/ len 2)))
(sort-loop (drop (/ len 2) l) (/ len 2)))))))))
(define (take n l)
(if (= n 0)
'()
(cons (car l) (take (sub1 n) (cdr l)))))
(define (drop n l)
(if (= n 0)
l
(drop (sub1 n) (cdr l))))
In general, mergesort is doing a lot of list manipulations, so it is much better to do things destructively by sorting sub parts "in-place". You can see the implementation of sort in PLT Scheme for example of a common code, which originated in SLIB. (It might look intimidating on first sight, but if you read the comments and ignore the knobs and the optimizations, you'll see it all there.)
Also, you should look at SRFI-32 for an extended discussion of a sorting interface.

Resources