我正在尝试从一个点列表中编写一个函数,该点列表返回从点p到距离p最远的点列表中的点的距离。我的要点如下:
((2 . 4) (3 . 6) (5 . 12) (-4 . 3) (8.4 . 9) (0 . -1))
我还做了一些抽象来检索通用汽车和cdr(为了更容易在代码中查看),以及列表本身的汽车和cdr。
(define (get-x p) (car p)
(define (get-y p) (car p)
(define (get-first-point pt-list)
(get-x pt-list))
(define (get-rest-points pt-list)
(get-y pt-list))
我已经写出了一个广义距离公式,我可以用于我选择的任何两点(请记住,我将汽车和cdr抽象为get-x和get-y)。
(define (distance a b)
(if (or (null? a) (null? b))
0
(sqrt (+ (expt (- (get-x a)
(get-x b)) 2)
(expt (- (get-y a)
(get-y b)) 2)))))
现在我有了这个,我知道我需要比较整个点集中的各种距离并选择最大返回值。我有一个部分解决方案,但没有一个对每个点都是正确的。
(define (max-distance p pt-list)
(if (null? pt-list)
0
(max (distance p (get-first-point pt-list)) ; 1
(distance p (get-first-point (get-rest-points pt-list))) ; 2
(distance p (get-first-point (get-rest-points (get-rest-points pt-list)))) ; 3
(distance p (get-first-point (get-rest-points (get-rest-points (get-rest-points pt-list))))) ; 4
(distance p (get-first-point (get-rest-points (get-rest-points (get-rest-points (get-rest-points pt-list)))))) ; 5
(distance p (get-first-point (get-rest-points (get-rest-points (get-rest-points (get-rest-points (get-rest-points pt-list))))))) ; 6
)
)
)
你可能会得到我(可怕)尝试做的事情的要点,但这就是我需要帮助的原因。
答案 0 :(得分:3)
在这种情况下,您希望在点列表中fold有一个 f 函数。函数 f 应该距离 d 并指向 x 并返回最大 d 和之间的距离> x 和您的特殊指定点 p 。我在其他一些答案中更详细地描述了折叠:
重点是,在折叠中,您可以获取函数,初始值和列表。您将函数应用于列表的第一个元素和初始值以生成一些新值。现在,您使用相同的函数,新值和列表的其余部分递归折叠。这基本上是这样的循环:
当前值 = 初始值
而 列表不为空 当前值 =使用 list 的第一个元素和当前值调用的函数结果
list = 列表的其余部分
返回 当前值
在Scheme中,尾部调用优化得到保证, 该循环。在您的情况下,您只需要确定初始值应该是什么,以及函数应该是什么。由于距离总是非负的,因此合理的初始值为零。功能有点复杂。 当前值将是一个距离,但 list 的第一个元素将是一个点。函数的结果需要是一个新的距离,新的距离应该是距离当前值的最大距离以及 list 中某些点与之间的距离特别的一点。在Racket中,这种折叠被称为foldl
,所以我们最终会得到这样的结果:
(define special-points '((2 . 4) (3 . 6) (5 . 12) (-4 . 3) (8.4 . 9) (0 . -1)))
(define (distance a b)
(let ((square (lambda (x)
(* x x))))
(sqrt (+ (square (- (car a) (car b)))
(square (- (cdr a) (cdr b)))))))
(define (max-distance point points)
(foldl (lambda (current-point current-distance)
(max current-distance
(distance point current-point)))
0
points))
> (max-distance '(4 . 12) special-points)
13.601470508735444
> (max-distance '(8 . 8) special-points)
13.0
> (max-distance '(2 . 5) special-points)
7.615773105863909
如果您不使用Racket,则必须编写自己的foldl
,但实际上并不是很难。 (这实际上并不像Racket的foldl
那么复杂,它可以采用任何正数的列表,但它适用于这种情况。)
(define (foldl function initial-value list)
(if (null? list)
initial-value
(foldl function
(function (car list) initial-value)
(cdr list))))
答案 1 :(得分:1)
get-y
应该使用cdr
,而不是car
。
get-x
和get-y
错过了右括号。
对于max-distance
,我会选择
(define (max-distance p pt-list)
(apply max (map (lambda (x) (distance p x)) pt-list)))
表示您不需要get-first-point
和get-rest-points
。
插图(使用(1.1)作为p):
> (map (lambda (x) (distance '(1 . 1) x)) '((2 . 4) (3 . 6) (5 . 12) (-4 . 3) (8.4 . 9) (0 . -1)))
'(3.1622776601683795 5.385164807134504 11.704699910719626 5.385164807134504 10.897706180660222 2.23606797749979)
> (apply max (map (lambda (x) (distance '(1 . 1) x)) '((2 . 4) (3 . 6) (5 . 12) (-4 . 3) (8.4 . 9) (0 . -1))))
11.704699910719626
根据您对“最远”的定义,您可能希望在表达式中包含abs
。
答案 2 :(得分:1)
计算car
points
的距离。该距离是cdr
points
的最大值或最大值。结果是一个简单的递归算法遍历点列表。
(define (max-distance-p p points)
(if (null? points)
0
(max (distance p (car points))
(max-distance-p p (cdr points)))))
如果您将0
作为空列表传递,则会返回points
;这可能有点可疑。如果是这样的话:
(define (max-distance-p p points)
(assert (not (null? points)))
(if (null? (cdr points))
(distance p (car points))
(max (distance p (car points))
(max-distance-p p (cdr points)))))