prolog找到最小值查询

时间:2013-05-03 00:42:30

标签: prolog minimum

如果我有以下格式的事实:

person(name,age).

如何编写查询以找到最年轻的人?

我尝试过使用递归,但我一直陷入无限循环。到目前为止,我所做的所有阅读都发现我需要使用!切割操作员。非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

您绝对不需要使用剪切运算符。我很难想象这个解决方案会是什么样子。

最简单的方法是进行此类查询:

youngest(person(Name,Age)) :-
  person(Name, Age),
  \+ (person(Name2,Age2), Name2 \= Name, Age2 < Age).

令人遗憾的是,这不是很有效,因为它可能必须为每个人搜索一次数据库,从而导致O(N ^ 2)性能。但应该清楚为什么它有效。

更快的解决方案是使用setof/3

youngest(person(Name, Age)) :-
  setof(Age-Name, person(Name,Age), [Age-Name|_]).

我们依赖于setof/3将对列表进行排序的事实,这将导致最年轻的人被移动到结果列表的开头以使其工作。它表现得更好,但它并没有清楚地读到这一切。

您可以使用标准库来解决SWI的这些问题,但我不确定您是否使用SWI而我自己没有使用它,但您可能会对此进行调查。它被称为aggregate

另一种方法是直接使用findall/3实现数据库,然后直接使用编写的谓词找到最小值。这样的解决方案可能看起来像这样:

youngest(Person) :-
  findall(person(Name,Age), person(Name,Age), [P1|Rest]),
  youngest(P1, Rest, Person).

youngest(Person, [], Person).
youngest(person(Name, Age), [person(N2,A2)|Rest], Person) :-
  Age < A2 -> youngest(person(Name, Age), Rest, Person)
            ; youngest(person(N2, A2),    Rest, Person).

然而,这似乎很多工作,即使它可能会给你最好的表现(应该是线性时间)。

答案 1 :(得分:1)

只需添加Daniel(+1)的(非常完整的)答案:图书馆(aggregate)可以进行此类搜索 - 以及更多:

youngest(Person) :-
    aggregate(min(Age,Pers), person(Pers,Age), min(_, Person)).

我认为值得研究,因为Prolog与数据库的类比,以及此语言中缺少的聚合运算符。