Пролог найти минимальное значение запроса
Если у меня есть факты в следующем формате:
person(name,age).
Как я могу написать запрос, чтобы найти самого молодого человека?
Я пытался использовать рекурсию, но я продолжал застрять в бесконечных циклах. Так далеко от всего чтения, которое я сделал, я узнал, что мне нужно использовать! режущий оператор. Любая помощь будет очень высоко ценится.
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, и я сам не использовал ее, но вы можете посмотреть на нее. Это называется агрегат.
Другой подход состоял бы в том, чтобы материализовать базу данных напрямую 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): библиотека ( агрегат) может выполнить такой поиск - и многое другое:
youngest(Person) :-
aggregate(min(Age,Pers), person(Pers,Age), min(_, Person)).
Я думаю, что это стоит изучить из-за аналогии Prolog с базами данных и отсутствующих операторов агрегации в этом языке.