如何编写谓词minmax(L,X,Y)以找出整数L列表中X的最小值和Y的最大值。
示例:
?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10, Y = 7.
答案 0 :(得分:3)
我们将list_minnum_maxnum/3
定义为list_minnum/2
:
list_minnum_maxnum([E|Es],Min,Max) :-
V is E,
list_minnum0_minnum_maxnum0_maxnum(Es,V,Min,V,Max).
list_minnum0_minnum_maxnum0_maxnum([] ,Min ,Min,Max ,Max).
list_minnum0_minnum_maxnum0_maxnum([E|Es],Min0,Min,Max0,Max) :-
V is E,
Min1 is min(Min0,V),
Max1 is max(Max0,V),
list_minnum0_minnum_maxnum0_maxnum(Es,Min1,Min,Max1,Max).
OP给出的示例查询:
?- list_minnum_maxnum([1,-10,1,0,7,7], Min,Max).
Min = -10,
Max = 7.
请注意,list_minnum_maxnum/3
的此实现适用于各种数字。
?- list_minnum_maxnum([1,-10,1,0,7.2,7,7], Min,Max).
Min = -10,
Max = 7.2.
如果您只关心处理整数,使用clpfd!
:- use_module(library(clpfd)).
我们将list_zmin_zmax/3
定义如下:
list_zmin_zmax([E|Es],Min,Max) :-
V #= E,
list_zmin0_zmin_zmax0_zmax(Es,V,Min,V,Max).
list_zmin0_zmin_zmax0_zmax([] ,Min ,Min,Max ,Max).
list_zmin0_zmin_zmax0_zmax([E|Es],Min0,Min,Max0,Max) :-
V #= E,
Min1 #= min(Min0,V),
Max1 #= max(Max0,V),
list_zmin0_zmin_zmax0_zmax(Es,Min1,Min,Max1,Max).
与以前一样使用样品:
?- list_zmin_zmax([1,-10,1,0,7,7], Min,Max).
Min = -10,
Max = 7.
OK!那么支持非整数?
?- list_zmin_zmax([1,-10,1,0,7.2,7,7], Min,Max).
ERROR: Domain error: `clpfd_expression' expected, found `7.2'
我们预计会收到错误,我们收到了错误...
请注意,感谢clpfd,我们也可以运行更多常规查询!
?- list_zmin_zmax([A,B], Min,Max).
A #>= Min, Max #>= A, Min #= min(A,B),
B #>= Min, Max #>= B, Max #= max(A,B).
答案 1 :(得分:2)
如上所述,您需要遍历列表,累积最小值和最大值。因此,假设您必须从头开始编写此代码,您需要做的第一件事是将问题分解为简单的步骤:
这会导致min/3
和max/3
,因此:
min(X,X,X).
min(X,Y,X) :- X < Y .
min(X,Y,Y) :- X > Y .
max(X,X,X).
max(X,Y,X) :- X > Y .
max(X,Y,Y) :- X < Y .
出于您的目的,如果您愿意,甚至可以将它们组合成单个谓词:
rank( X , X , X , X ) .
rank( X , Y , X , Y ) :- X < Y .
rank( X , Y , Y , X ) :- X > Y .
Prolog中一个非常典型的编程模式是一个简单的公共API谓词,它调用一个执行实际工作的私有“worker”谓词。通常,工作者谓词将携带简化工作的临时“累加器”变量。您的公共谓词可能如下所示:
minmax([X|Xs],Min,Max) :- minmax_scan( Xs , X , X , Min , Max ).
在这里,您的公共API谓词接受非空列表,将worker谓词与列表头部一起使用的最小/最大累加器播种,然后使用列表尾部调用worker谓词。
您的工作者谓词可能如下所示:
% if the list is empty, we've solved the puzzle, right?
minmax_scan( [] , Min , Max , Min , Max ) .
% if the list is non-empty, we need to compare its head to
% the current value for min/max to determine the new values for min/max
% (which might be the same), and then recurse down on the tail of the list
minmax_scan( [X|Xs] , CurrMin , CurrMax , Min , Max ) :-
min( X , CurrMin , NextMin ) ,
max( X , CurrMax , NextMax ) ,
minmax_scan( Xs , NextMin , NextMax , Min , Max )
.
容易!
答案 2 :(得分:1)
从列表中取出第一个值,然后检查列表中的每个其他元素,选择较低/较高值作为临时最小值/最大值。
如果在列表末尾,您同时拥有......
minmax([First|Rest], Min, Max) :-
minmax(Rest, First, First, Min, Max).
minmax([], Min, Max, Min, Max).
minmax([Value|Ns], MinCurr, MaxCurr, Min, Max) :-
....
minmax(Ns, MinNext, MaxNext, Min, Max).
我会让你在递归调用之前编写测试(即填充点!)
编辑只是为了指出库(aggregate),可以在几个Prolog系统中找到:
1 ?- [user].
minmax(L, X, Y) :- aggregate( (min(E), max(E)), member(E, L), (X, Y) ).
|:
true.
2 ?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10,
Y = 7.
答案 3 :(得分:1)
这里有些令人费解,有点复杂。
is_minmax(A,B-D,C-E) :-
D is min(...),
E is max(...) .
pair(A,B,A-B).
minmax(L,MIN,MAX) :-
L=[A|_], length(L,N), N2 is N-1,
length(L2,N2), append(L2,[MIN],L22),
length(L3,N2), append(L3,[MAX],L33),
maplist(pair, [A|L2], L22, KL2),
maplist(pair, [A|L3], L33, KL3),
maplist(is_minmax, L, KL2, KL3).
(适用于SWI Prolog)。尝试找出代替点...
的内容。