Search code examples
listschememedian

Scheme - Get median from a list of median from already sorted list


The program i'm attempting to create is one that can perform a range of math functions from average to std-dev and so on but the one that im getting tripped up on is median. The list is already sorted so how can i get the length of this list to determine whether even or odd and then get the median from that. Current code below. Quite new to Scheme so the syntax is quite confusing to me still.

CODE

(define make-tswb
  (lambda ()
    (let ((records '()))
      (lambda (command . args)
        (cond
          ((equal? command 'empty?)
           (null? records))
          ((equal? command 'add!)
           (set! records (cons (car args) records)))
          ((equal? command 'get)
           (letrec ((sort-records (lambda (r) (sort r (lambda (x y) (<= (car x) (car y)))))))
             (if (null? args)
                 (sort-records records)
                 (sort-records (filter(car args) records)))))
          ((equal? command 'analytic)
           (cond
             ((= (length args) 1)
              ((car args) records))
             ((= (length args) 2)
              ((car args) (filter (cadr args) records))))))))))


(define listofVal
  (lambda (lst)
    (if (null? lst)
        '()
        (sort (map cadddr lst) <))))

(define median
  (lambda (medianList)
    (let ((values (listofVal medianList)))
      (let ((len (length medianList)))
      // ??????????


(define tswb (make-tswb))
(tswb 'add!     '(2 123 "temp1"  76.1))
(tswb 'add!     '(1 123 "temp1"  72.0))
(tswb 'add!     '(1 123 "temp1"  75.0))
(tswb 'analytic median)

Solution

  • According to this page, you need to handle two cases:

    1. Length of the list is even number.
    2. It is not an even number.

    For the first case, you need to take two values in the middle, count a sum of them and then divide by two. For the second case, you need to find the middle of the sorted list and this value will be the median.

    So, I think, this should work for you:

    (define (count-median-for-even len listOfVal)
      (/ (+ (list-ref listOfVal (round (- (/ len 2) 1)))
            (list-ref listOfVal (round (/ len 2)))) 2))
    
    (define (count-median-for-odd len listOfVal)
      (list-ref listOfVal (round (/ len 2))))
    
    (define median
      (lambda (medianList)
        (let ((values (listofVal medianList)))
          (let ((len (length medianList)))
            (if (even? len) (count-median-for-even len values) (count-median-for-odd len values))))))
    

    Having tested this on the three test-cases from the link above, I can say this must do the job for you.