简而言之:如何在列表中找到最小值? (感谢kaarel的建议)
长篇故事:
我在amzi prolog中创建了一个加权图并给出了2个节点,我能够检索路径列表。但是,我需要在此路径中找到最小值,但无法遍历列表以执行此操作。请问您如何确定清单中的最小值?
我的代码目前看起来像这样:
arc(1,2). arc(2,3). arc(3,4). arc(3,5). arc(3,6). arc(2,5). arc(5,6). arc(2,6). path(X,Z,A) :- (arc(X,Y),path(Y,Z,A1),A is A1+1;arc(X,Z), A is 1).
因此,“键入findall(Z,路径(2,6,Z),L)。”在听众中允许我获得一个列表[3,2,2,1]。 我需要从这里检索最小值并将其乘以一个数量。有人可以建议如何检索最小值?谢谢!
答案 0 :(得分:19)
通常使用所谓的“滞后论证”来从第一个参数索引中受益:
list_min([L|Ls], Min) :-
list_min(Ls, L, Min).
list_min([], Min, Min).
list_min([L|Ls], Min0, Min) :-
Min1 is min(L, Min0),
list_min(Ls, Min1, Min).
此模式称为 fold (从左侧开始),foldl/4
(最近的SWI版本中提供)允许您将其写为:
list_min([L|Ls], Min) :- foldl(num_num_min, Ls, L, Min).
num_num_min(X, Y, Min) :- Min is min(X, Y).
请注意,这不能用于所有方向,例如:
?- list_min([A,B], 5).
is/2: Arguments are not sufficiently instantiated
如果您在推理整数,就像您的示例中的情况一样,我建议您使用CLP(FD)约束来自然地推广谓词。而不是(is)/2
,只需使用(#=)/2
并从更具声明性的解决方案中受益:
:- use_module(library(clpfd)).
list_min([L|Ls], Min) :- foldl(num_num_min, Ls, L, Min).
num_num_min(X, Y, Min) :- Min #= min(X, Y).
这可以用作真正的关系,适用于所有方向,例如:
?- list_min([A,B], 5).
得到以下特性:
A in 5..sup,
5#=min(B, A),
B in 5..sup.
答案 1 :(得分:13)
这对我来说是正确的(from here)。
min_in_list([Min],Min). % We've found the minimum
min_in_list([H,K|T],M) :-
H =< K, % H is less than or equal to K
min_in_list([H|T],M). % so use H
min_in_list([H,K|T],M) :-
H > K, % H is greater than K
min_in_list([K|T],M). % so use K
答案 2 :(得分:3)
%Usage: minl(List, Minimum).
minl([Only], Only).
minl([Head|Tail], Minimum) :-
minl(Tail, TailMin),
Minimum is min(Head, TailMin).
第二个规则执行递归,用英语“获取尾部的最小值,并将Minimum设置为较小的值和头部”。第一个规则是基本情况,“列表的最小值是列表中唯一的值”。
测试:
| ?- minl([2,4,1],1).
true ?
yes
| ?- minl([2,4,1],X).
X = 1 ?
yes
你可以用它来检查第一种情况下的值,或者你可以让prolog计算第二种情况下的值。
答案 3 :(得分:3)
SWI-Prolog提供图书馆(汇总)。广义和性能明智。
:- [library(aggregate)].
min(L, M) :- aggregate(min(E), member(E, L), M).
答案 4 :(得分:2)
没有“是”的解决方案。
min([],X,X).
min([H|T],M,X) :- H =< M, min(T,H,X).
min([H|T],M,X) :- M < H, min(T,M,X).
min([H|T],X) :- min(T,H,X).
答案 5 :(得分:2)
这对我来说可以:
minimumList([X], X). %(The minimum is the only element in the list)
minimumList([X|Q], M) :- % We 'cut' our list to have one element, and the rest in Q
minimumList(Q, M1), % We call our predicate again with the smallest list Q, the minimum will be in M1
M is min(M1, X). % We check if our first element X is smaller than M1 as we unstack our calls
答案 6 :(得分:1)
SWI-Prolog有min_list/2
:
min_list(+List, -Min)
True if Min is the smallest number in List.
其定义位于library/lists.pl
min_list([H|T], Min) :-
min_list(T, H, Min).
min_list([], Min, Min).
min_list([H|T], Min0, Min) :-
Min1 is min(H, Min0),
min_list(T, Min1, Min).
答案 7 :(得分:0)
感谢回复。很有用。我也进行了实验并开发了这个答案:
% if list has only 1 element, it is the smallest. also, this is base case.
min_list([X],X).
min_list([H|List],X) :-
min_list(List,X1), (H =< X1,X is H; H > X1, X is X1).
% recursively call min_list with list and value,
% if H is less than X1, X1 is H, else it is the same.
不确定如何在算法上判断答案有多好,但它确实有效!我会很感激任何反馈。谢谢!
答案 8 :(得分:0)
min([Second_Last, Last], Result):-
Second_Last < Last
-> Result = Second_Last
; Result = Last, !.
min([First, Second|Rest], Result):-
First < Second
-> min([First|Rest], Result)
; min([Second|Rest], Result).
应该有效。
答案 9 :(得分:0)
与andersoj相似,但使用剪切而不是双重比较:
min([X], X).
min([X, Y | R], Min) :-
X < Y, !,
min([X | R], Min).
min([X, Y | R], Min) :-
min([Y | R], Min).
答案 10 :(得分:0)
这很有效,而且似乎相当有效。
min_in_list([M],M).
min_in_list([H|T],X) :-
min_in_list(T,M),
(H < M, X = H; X = M).
min_list(X,Y) :- min_in_list(X,Y), !.
答案 11 :(得分:0)
该程序可能很慢,但是我想尽可能地编写正确的代码。
最小(列表,最小值):- 排序(列表,[Min | _])。
答案 12 :(得分:-1)
%在列表中找到最小值
min([Y],Y):-!.
min([H|L],H):-min(L,Z),H=<Z.
min([H|L],Z):-min(L,Z),H>=Z.
%所以想到了什么!