序言中列表列表中的最小值

Posted

技术标签:

【中文标题】序言中列表列表中的最小值【英文标题】:minimum in list of lists in prolog 【发布时间】:2016-04-14 10:40:30 【问题描述】:

你好,我有一个这样的列表:

[[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]]

列表列表... 我想找到内部列表中的最小数量 在这种情况下,我想返回 D=2 和 L=[a,b,d]

我试过这个代码:

minway([[N|L]],N,L).
minway([[M|L1]|L2],D,_):- M<D, minway(L2,M,L1).
minway([[M|_]|L2],D,L):- M>=D, minway(L2,D,L).

但我得到了错误:

</2: Arguments are not sufficiently instantiated
   Exception: (8) minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]], _G7777, _G7778) ? 
   creep

对于这个运行语句:

minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]],D,L).

结果必须是:

D=2.
L=[a,b,d].

我的问题在哪里? 以及如何解决?

很多

【问题讨论】:

【参考方案1】:

首先,切换到更好的数据表示:使用Key-Value,而不是Key-Value

然后,定义minway_/3 基于 iwhen/2, ground/1, keysort/2,和 member/2,像这样:

minway_(Lss, N, Ls) :-
   iwhen(ground(Lss), (keysort(Lss,Ess), Ess = [N-_|_], member(N-Ls, Ess))).

使用 SICStus Prolog 4.5.0 的示例查询:

| ?- minway_([3-[a,b,c,d],2-[a,b,d],5-[d,e,f],2-[x,t,y]], N, Ls).
N = 2, Ls = [a,b,d] ? ;
N = 2, Ls = [x,t,y] ? ;
no

【讨论】:

【参考方案2】:

有几个基本问​​题。

您的问题在于您对列表的表示。您的谓词似乎假设,例如,[3, [a,b,c]] 表示为[3 | [a,b,c]],但事实并非如此。列表[3 | [a,b,c]] 是以3 作为头部的列表,[a,b,c] 作为列表的其余部分或尾部。换句话说,[3 | [a,b,c]] 就是[3, a, b, c]

因此,您的基本情况是:

minway([[N,L]], N, L).

第二个问题在您的其他谓词从句中。 D 没有起点。换句话说,它从来没有被赋予一个值,所以你会得到一个实例化错误。如果其中一个变量没有值,则无法比较 N &gt; D

当从头开始做最小值或最大值时,一种常见的方法是首先假设第一个元素是候选结果,然后在递归的每一步找到更好的元素时替换它。这也意味着您需要在每次递归调用时随身携带最后一个候选者,以便添加额外的参数:

minway([[N,L]|T], D, R) :-
    minway(T, N, L, D, R).

minway([], D, R, D, R).            % At the end, so D, R is the answer
minway([[N,L]|T], Dm, Rm, D, R) :-
    (   N < Dm
    ->  minway(T, N, L, D, R)      % N, L are new candidates if N < Dm
    ;   minway(T, N, Dm, Rm, D, R) % Dm, Rm are still best candidate
    ).

在 Prolog 中,您可以稍微简化这一点,因为 Prolog 有一个更通用的术语比较运算符,@&lt;@&gt; 等,它可以很聪明地比较更复杂的术语。例如,[2, [d,e,f]] @&lt; [3, [a,b,c]] 为真,因为2 &lt; 3 为真。然后我们可以写:

minway([H|T], D, R) :-
    minway(T, H, D, R).

minway([], [D, R], D, R).
minway([H|T], M, D, R) :-
    (   H @< M
    ->  minway(T, H, D, R)
    ;   minway(T, M, D, R)
    ).

【讨论】:

【参考方案3】:

您可以通过使用最小谓词来做到这一点。 Findall 会很有帮助。

min([X],X).
min([H|T],Min):-
    min(T,TMin),
    H>TMin,
    Min is TMin.
min([H|T],Min):-
    min(T,TMin),
    H=<TMin,
    Min is H.

minway(List,D,L):-
    findall(Value,member([Value,_],List),VList),
    min(VList,Min),
    D=Min,
    findall(EList,member([Min,EList],List),L).

?-minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]],D,L).
D = 2,
L = [[a, b, d]]

【讨论】:

【参考方案4】:

尝试库(聚合):

?- aggregate_all(min(X,Y), 
       member([X,Y], [[3,[a,b,c,d]],
                      [2,[a,b,d]],
                      [5,[d,e,f]]]), 
       min(D,L)).
D = 2,
L = [a, b, d].

参见此处:

可回溯谓词上的聚合运算符https://www.swi-prolog.org/pldoc/man?section=aggregate

【讨论】:

以上是关于序言中列表列表中的最小值的主要内容,如果未能解决你的问题,请参考以下文章

在列表列表中查找最小值[重复]

如何从python列表中的最小值开始?

列表字典中的Python最小值

查找列表中的最小元素(递归) - Python

python 怎么取列表中最小的数

如何显示列表中的最小值和最大值?