简而言之:如何在列表中找到最小值? (感谢 kaarel 的建议)
很长的故事:
我在 amzi prolog 中创建了一个加权图,并给出了 2 个节点,我能够检索路径列表。但是,我需要在此路径中找到最小值,但无法遍历列表来执行此操作。我可以就如何确定列表中的最小值征求您的意见吗?
我的代码目前看起来像这样:
弧(1,2)。
弧(2,3)。
弧(3,4)。
弧(3,5)。
弧(3,6)。
弧(2,5)。
弧(5,6)。
弧(2,6)。
路径(X,Z,A): -
(弧(X,Y),路径(Y,Z,A1),A是A1+1;弧(X,Z),A是1)。
因此,'键入 findall(Z,path(2,6,Z),L).'在听众中,我可以得到一个列表 [3,2,2,1]。
我需要从这里检索最小值并将其乘以一个数量。有人可以就如何检索最小值提出建议吗?谢谢!
最佳答案
通常使用所谓的“滞后参数”来从第一参数索引中受益:
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).
这种模式称为折叠(从左侧开始),而
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.
关于list - Prolog,在列表中找到最小值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3965054/