【发布时间】:2013-04-27 07:49:19
【问题描述】:
如果我有以下格式的事实:
person(name,age).
如何编写查询以找到最年轻的人?
我曾尝试使用递归,但一直陷入无限循环。到目前为止,从我所做的所有阅读中,我发现我需要使用 !切割运算符。任何帮助将不胜感激。
【问题讨论】:
如果我有以下格式的事实:
person(name,age).
如何编写查询以找到最年轻的人?
我曾尝试使用递归,但一直陷入无限循环。到目前为止,从我所做的所有阅读中,我发现我需要使用 !切割运算符。任何帮助将不胜感激。
【问题讨论】:
您绝对不需要使用 cut 运算符。我很难想象那个解决方案会是什么样子。
最简单的做法是进行这种查询:
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).
但是,这似乎需要做很多工作,尽管它可能会为您提供最佳性能(应该是线性时间)。
【讨论】:
[user].吗?
\+ 之后有一个空格,或者在它之后的内容周围放置另一组括号。你用的是什么 Prolog?
只是添加到 Daniel (+1) 的(非常完整的)答案中:library(aggregate) 可以进行此类搜索 - 以及更多:
youngest(Person) :-
aggregate(min(Age,Pers), person(Pers,Age), min(_, Person)).
我认为值得研究,因为 Prolog 与数据库的类比,以及该语言中缺少聚合运算符。
【讨论】: