简体   繁体   中英

Sorting a list of sublists in scheme

IN SCHEME

I am trying to write a section of code to sort a list of sublists, using the difference between to elements of each sublist. What i mean is:

ie.,

list of sublists: '('(ted 10 4) '(barbie 10 5) '(car 10 7) '(ball 10 6))

and i want to sort the list based on the difference between the 2nd and 3rd element of each sublist list thus the sorted list should look like in ascending order (lowest to highest):

'('(car 10 7) '(ball 10 6) '(barbie 10 5) '(teddy 10 4))

I have created accessors for the sublists:

(define (access-name x) (car x))
(define (access-aquprice x)(cadr x))
(define (access-saleprice x)(caddr x))

the sort loop is confusing me,please help! :)

So far all I have is:

(define (sortlist curr) 
  (if (null? curr)
      (curr) 
      (if (> 
           (diff (access-aquprice (car toylist))  (access-saleprice (car toylist))) 
           (diff (access-aquprice (cadr toylist)) (access-saleprice (cadr toylist))))
          ("hello") 
          "goodbye")))

Disclaimer: this is the first sort I ever write myself. It may not be bug-free

So you first have to write a basic sort. I suggest you look at this page and pick one. I chose Merge sort since the Wikipedia illustration is nice and it's easy to implement it recursively.

We'll start with sorting a simple list.

So, first the merge:

(define (merge lst1 lst2)
  (cond 
    ((null? lst1) lst2)
    ((null? lst2) lst1)
    ((> (car lst1) (car lst2)) 
     (cons (car lst2) (merge lst1 (cdr lst2))))
    (else
     (cons (car lst1) (merge (cdr lst1) lst2)))))

then the merge sort:

(define (merge-sort lst)
  (define len (length lst))
  (if (<= len 1)
      lst
      (let ((n (quotient len 2)))
        (merge (merge-sort (take lst n)) (merge-sort (drop lst n))))))

( take and drop are defined in SRFI-1 if needed)

Trying:

> (merge-sort '(7 3 0 1 5 8))
'(0 1 3 5 7 8)
> (merge-sort '())
'()
> (merge-sort '(3 14 15 9 26 53 58 97 23))
'(3 9 14 15 23 26 53 58 97)

Looks nice.

Now we'll extend it to use a custom compare function:

(define (merge-sort compare lst)

  (define (merge lst1 lst2)
    (cond 
      ((null? lst1) lst2)
      ((null? lst2) lst1)
      ((compare (car lst1) (car lst2)) 
       (cons (car lst2) (merge lst1 (cdr lst2))))
      (else
       (cons (car lst1) (merge (cdr lst1) lst2)))))

  (define (inner-sort lst)
    (define len (length lst))
    (if (<= len 1)
        lst
        (let ((n (quotient len 2)))
          (merge (inner-sort (take lst n)) (inner-sort (drop lst n))))))

  (inner-sort lst))

then

> (merge-sort > '(7 3 0 1 5 8))
'(0 1 3 5 7 8)
> (merge-sort < '(7 3 0 1 5 8))
'(8 7 5 3 1 0)

Finally, creating a custom compare function for your case:

(merge-sort 
 (lambda (a b) (> (- (access-aquprice a) (access-saleprice a))
                  (- (access-aquprice b) (access-saleprice b))))
 '((ted 10 4) (barbie 10 5) (car 10 7) (ball 10 6)))

yields

'((car 10 7) (ball 10 6) (barbie 10 5) (ted 10 4))

I know that the question is 3 years old, and you are not allowed to use the built-in sort function, but just in case somebody needs it:

(sort (lambda (x y) (< (- (cadr x) (caddr x))
                       (- (cadr y) (caddr y))))
      '((ted 10 4) (barbie 10 5) (car 10 7) (ball 10 6)))

returns ((car 10 7) (ball 10 6) (barbie 10 5) (ted 10 4))

Cheers!
Andres

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM