I\'m currently trying to write a function from a list of points that returns the distance from a point p to a point in my point list that is farthest away from p. My list of poi
get-y
should use cdr
, not car
.
get-x
and get-y
miss a closing parenthesis.
For max-distance
, I'd go for
(define (max-distance p pt-list)
(apply max (map (lambda (x) (distance p x)) pt-list)))
which means that you don't need get-first-point
and get-rest-points
.
Illustration (using (1 . 1) as 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
Depending on your definition of "farthest" you may want to include abs
in the expression.
This is a case where you want to fold a function f over your list of points. The function f should take a distance d and point x and return the maximum d and the distance between x and your special designated point p. I've described folds in a bit more detail in some other answers:
The main point is that in a fold, you take a function, an initial value, and a list. You apply the function to the first element of the list and the initial value to produce some new value. Now you recursively fold with the the same function, the new value, and the rest of the list. This is essentially a loop like this:
current value = initial value
while list is not empty
current value = result of function called with first element of list and current value
list = rest of list
return current value
In Scheme, where tail call optimization is guaranteed, it is that loop. In your case, you just need to determine what the initial value should be, and what the function should be. Since distances are always non-negative, a reasonable initial value is zero. The function is a bit more complicated. current value will be a distance, but the first element of list will be a point. The result of the function needs to be a new distance, and the new distance should be the maximum of the distance current value and the distance between some the point from list and the special point. In Racket, this kind of fold is called foldl, so we end up with something like this:
(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
If you're not using Racket, you'll have to write your own foldl
, but it's really not very hard. (This actually isn't quite as sophisticated as Racket's foldl
, which can take any positive number of lists, but it will work for this case.)
(define (foldl function initial-value list)
(if (null? list)
initial-value
(foldl function
(function (car list) initial-value)
(cdr list))))
Compute the distance to the car
of points
. Either that distance is the maximum or the maximum from the cdr
of points
is. Result is a simple recursive algorithm traversing the list of points.
(define (max-distance-p p points)
(if (null? points)
0
(max (distance p (car points))
(max-distance-p p (cdr points)))))
The 0
is returned if you pass in points
as an empty list; that might be a bit questionable. If so:
(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)))))