Exercise 160: Design a program that sorts lists of mail messages by date:
(define-struct mail (from date message)) ; A Mail Message is a structure: ; – (make-mail String Number String) ; interp. (make-mail f d m) represents text m sent by ; f, d seconds after the beginning of time
Also develop a program that sorts lists of mail messages by name. To compare two strings alphabetically, use the string<? primitive.
***
This exercise was pretty easy - the answer to most of this was given more or less directly in the previous example of sorting a list of numbers. To make this more challenging I tried to do this without referring back to the previous example.
First I defined a series of structs that contain some predefined emails. This is just to make to check-expects easier to code and to read.
; Number List-of-numbers -> List-of-numbers
(define-struct mail (from date message))
(define FIRST (make-mail "dave" 0 "hello"))
(define SECOND (make-mail "john" 10 "hello"))
(define THIRD (make-mail "andrew" 20 "hello"))
(define FOURTH (make-mail "andrew" 40 "hello"))
; List-of-mails -> List-of-mails
; produces a version of alom, sorted by date in descending order
(check-expect (sort-date-> empty) empty)
(check-expect (sort-date-> (list THIRD FOURTH FIRST))
(list FOURTH THIRD FIRST))
(check-expect (sort-date-> (list THIRD SECOND FIRST))
(list THIRD SECOND FIRST))
(check-expect (sort-date-> (list FIRST SECOND THIRD))
(list THIRD SECOND FIRST))
(define (sort-date-> alom)
(cond
[(empty? alom) empty]
[else (insert-date (first alom) (sort-date-> (rest alom)))]))
Here we insert our date in to the already sorted list. To simplify this I have made a helper function more-recent? which will compare the dates on two emails and let us know which is more recent.
; insert n into the sorted list of date alon
(define (insert-date n alon)
(cond [(empty? alon) (cons n empty)]
[else (cond [(more-recent? n (first alon)) (cons n alon)]
[else (cons (first alon)
(insert-date n (rest alon)))])]))
This is the helper function to determine which of two emails is more recent. We could do this inline in the insert-date method, but this lends itself to more clarity.
(define (more-recent? email-1 email-2)
(>= (mail-date email-1) (mail-date email-2)))
The sort order is not specified, so I will assume we are sorting from most recent -> least recent
(check-expect (insert-date FIRST empty) (list FIRST))
(check-expect (insert-date FIRST (list SECOND ))
(list SECOND FIRST))
(check-expect (insert-date SECOND (list FIRST))
(list SECOND FIRST))
(check-expect (insert-date SECOND (list THIRD FIRST))
(list THIRD SECOND FIRST));;;
As this is so similar to sorting by date I won't document what I am doing in as much detail.
I have created some more structs for this - I could have rigged the original ones so that they were both alphabetically and date sorted, but creating new ones seems to be more honest.
(define NFIRST (make-mail "andrew" 20 "hello"))
(define NSECOND (make-mail "bob" 410 "hello"))
(define NTHIRD (make-mail "charlie" 20 "hello"))
(define NFOURTH (make-mail "dave" 4 "hello"))
; List-of-mails -> List-of-mails
; produces a version of alom, sorted by name in descending order
(check-expect (sort-name-> empty) empty)
(check-expect (sort-name-> (list NTHIRD NFOURTH NFIRST))
(list NFOURTH NTHIRD NFIRST))
(check-expect (sort-name-> (list NTHIRD NSECOND NFIRST))
(list NTHIRD NSECOND NFIRST))
(check-expect (sort-name-> (list NFIRST NSECOND NTHIRD))
(list NTHIRD NSECOND NFIRST))
(define (sort-name-> alom)
(cond
[(empty? alom) empty]
[else (insert-by-name (first alom) (sort-name-> (rest alom)) )]))
; insert n into the sorted list of mails alom
(define (insert-by-name n alom)
(cond [(empty? alom) (cons n empty)]
[else (cond [(alphabetically-earlier? n (first alom))
(cons n alom)]
[else (cons (first alom)
(insert-by-name n (rest alom)))])]))
; sort order not specified, so will assume sort from most recent -> least recent
(check-expect (insert-by-name NFIRST empty) (list NFIRST))
(check-expect (insert-by-name NFIRST (list NSECOND ))
(list NSECOaND NFIRST))
(check-expect (insert-by-name NSECOND (list NFIRST))
(list NSECOND NFIRST))
(check-expect (insert-by-name NSECOND (list NTHIRD NFIRST))
(list NTHIRD NSECOND NFIRST))
; utility function to determine which of two emails is more recent
(define (alphabetically-earlier? email-1 email-2)
(string>? (mail-from email-1) (mail-from email-2)))
No comments:
Post a Comment