Короткий ответ: нет, ничего действительно «лучшего» не существует с точки зрения того, чтобы быть всегда правильным, простым в реализации и в то же время эффективным.
Небольшая поправка: достаточно написать
data(MaxID, MaxName, MaxAge),
\+ (data(ID, Name, Age), MaxAge < Age)
(как было предложено @false в комментарии к вашему вопросу)
Вы также можете увидеть этот вопрос и ответы. В этом ответе подробно рассказывается, когда и почему использование setof/3
может быть проблематичным. Это может быть важно для вашего варианта использования.
Другой способ сделать это (не упомянутый в очень полезном ответе @CapelliC) - собрать все решения из вашего предиката и отсортировать их с помощью ключа. Если вы используете SWI-Prolog или другой Prolog с 4- версия аргумента sort, позволяющая выбрать сравнение и ключ внутри термина, например:
bagof(data(ID, Name, Age), data(ID, Name, Age), All),
sort(3, @>=, All, [data(Max_ID, Max_Name, Max_Age)|_])
Пока ваш data/3
представляет собой просто таблицу фактов, ее можно безопасно использовать.
Это, конечно, не работает, если у вас есть эквивалентные, но не равные элементы в списке, такие как data(10, john, 34)
и data(101, jane, 34)
. В вопросе и ответе, которые я связал, есть примеры того, как с этим бороться, но опять же, я действительно не думаю, что это становится «лучше». Это может быть более эффективно. Я настоятельно рекомендую тщательно рассмотреть ваш вариант использования и измерить производительность, если вы считаете, что это может быть узким местом.
Изучение реализации библиотеки (агрегата), предложенной @CapelliC, очевидно, что она предназначена именно для этого варианта использования: она может найти минимум, максимум, сумму и т. д. в постоянной памяти и касаясь каждого факта только один раз, и возвращается для построения всего списка, если это необходимо.
person
Community
schedule
05.03.2017
ID \= MinID
делает его немного быстрее. - person false   schedule 04.03.2017