Scheme - 如何使用用户定义的排序和平均函数查找中值?

时间:2016-04-26 00:55:29

标签: scheme racket

我是Scheme的新手,我已经碰壁了。我有我的排序和平均功能,我正在尝试更改我在此网站上找到的中位数函数。但是,无论我尝试什么,我都会在中位函数中有多个表达式时出现错误,或者当我尝试在中位函数中使用sort时,它是“未定义的”。

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

我正在尝试编辑中值函数以首先对列表进行排序,如果有偶数个元素,我需要取列表的平均值,并使用最接近平均值的元素。

任何帮助将不胜感激,谢谢你。

2 个答案:

答案 0 :(得分:0)

我认为你误解了median的定义。下面是一个非常简单(如果不是特别有效)的实现:

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

它的定义如下:

(median '())
=> The list is empty
(median '(3 2 1 5 4))
=> 3
(median '(6 4 3 1 2 5))
=> 3.5

答案 1 :(得分:0)

就像我在评论中所说,你想要的不是let,而是它的功能组合。

您目前的中位数函数是:

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

但正如奥斯卡·洛佩兹指出的那样,这并不能正确计算中位数。但是,它做了一些工作,所以保持它。将其重命名为median-helper或其他内容。

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

然后你可以使用函数组合来定义“真实”中值函数:

(define (median lst)
   (median-helper (sort1 lst)))

这将返回奇数长度列表的中间元素,以及偶数长度列表的中间两个元素。如果这是你想要的,那很好。如果没有,那么您可以通过返回median-helper的第二种情况中的平均值来修复cond。因此,不是(list (car L1) (cadr L1)),而是(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)))