适度短的和基本的方式来写它,没有findall
和aggregate
等是这样的。
首先,发现坐标两个列表之间的欧几里得距离谓词:
d([P|Ps], [Q|Qs], D) :-
sum_diff_sq(Ps, Qs, (P-Q)^2, R),
D is sqrt(R).
sum_diff_sq([], [], V, V).
sum_diff_sq([P|Ps], [Q|Qs], V0, V+V0) :-
sum_diff_sq(Ps, Qs, (P-Q)^2, V).
这将计算一对坐标之间的距离,每个号码的列表。
?- d([1], [1], D).
D = 0.0.
?- d([1], [2], D).
D = 1.0.
?- d([1,1], [2,2], D).
D = 1.4142135623730951.
?- d([1,1,1], [2,2,2], D).
D = 1.7320508075688772.
?- d([1,1,1,1], [2,2,2,2], D).
D = 2.0.
然后,为了计算所有可能距离:
points_distances([], []).
points_distances([P|Ps], Ds) :-
rest_distances(Ps, P, Ds, Ds0),
points_distances(Ps, Ds0).
points_distances/2
使得头部和各坐标的在列表的尾部之间的距离的列表,递归(因此在该距离每对之间会有结果)。
rest_distances([], _, Back, Back).
rest_distances([P|Ps], X, [D|Ds], Back) :-
d(P, X, D),
rest_distances(Ps, X, Ds, Back).
这只是计算坐标列表和坐标之间的距离。结果是一个差异列表。
要使用此:
?- points_distances([[1,1],[1,2],[6,3],[8,2]], D).
D = [1.0, 5.385164807134504, 7.0710678118654755, 5.0990195135927845, 7.0, 2.23606797749979].
?- points_distances([[1,2,3],[2,3,4],[1,7,3],[1,6,3]], D).
D = [1.7320508075688772, 5.0, 4.0, 4.242640687119285, 3.3166247903554, 1.0].
如果你愿意,你可以“拯救”,这对坐标是在彼此的距离。例如,改变rest_distances/4
从第二条款的头:
rest_distances([P|Ps], X, [D|Ds], Back)
到:现在
rest_distances([P|Ps], X, [D-pq(X,P)|Ds], Back)
,重装程序后,可以排序的points_distances/2
结果和采取的第一个元素它,就像在其他答案:
?- points_distances([[1,2,3],[2,3,4],[1,7,3],[1,6,3]] , D),
keysort(D, [Min_dist-pq(P,Q)|_]).
D = [1.7320508075688772-pq([1, 2, 3], [2, 3, 4]),
5.0-pq([1, 2, 3], [1, 7, 3]),
4.0-pq([1, 2, 3], [1, 6, 3]),
4.242640687119285-pq([2, 3, 4], [1, 7, 3]),
3.3166247903554-pq([2, 3|...], [1, 6|...]),
1.0-pq([1|...], [1|...])],
Min_dist = 1.0,
P = [1, 7, 3],
Q = [1, 6, 3].