Учитывая следующие факты в базе данных:
foo(a, 3).
foo(b, 2).
foo(c, 4).
foo(d, 3).
foo(e, 2).
foo(f, 6).
foo(g, 3).
foo(h, 2).
Я хочу собрать все первые аргументы, которые имеют наименьший второй аргумент, плюс значение второго аргумента. Первая попытка:
find_min_1(Min, As) :-
setof(B-A, foo(A, B), [Min-_|_]),
findall(A, foo(A, Min), As).
?- find_min_1(Min, As).
Min = 2,
As = [b, e, h].
Вместо setof/3
я мог бы использовать aggregate/3
:
find_min_2(Min, As) :-
aggregate(min(B), A^foo(A, B), Min),
findall(A, foo(A, Min), As).
?- find_min_2(Min, As).
Min = 2,
As = [b, e, h].
Примечание
Это дает те же результаты только в том случае, если я ищу минимум числа. Если задействовано арифметическое выражение, результаты могут быть другими. Если задействовано не число, aggregate(min(...), ...)
выдаст ошибку!
Или вместо этого я могу использовать полный список, отсортированный по ключам:
find_min_3(Min, As) :-
setof(B-A, foo(A, B), [Min-First|Rest]),
min_prefix([Min-First|Rest], Min, As).
min_prefix([Min-First|Rest], Min, [First|As]) :-
!,
min_prefix(Rest, Min, As).
min_prefix(_, _, []).
?- find_min_3(Min, As).
Min = 2,
As = [b, e, h].
Наконец, на вопрос (ы):
Могу ли я сделать это напрямую с библиотекой (агрегатом)? Такое ощущение, что можно....
Или есть такой предикат, как
std::partition_point
из стандартной библиотеки C++?Или есть более простой способ сделать это?
РЕДАКТИРОВАТЬ:
Чтобы быть более описательным. Скажем, был (библиотечный) предикат partition_point/4
:
partition_point(Pred_1, List, Before, After) :-
partition_point_1(List, Pred_1, Before, After).
partition_point_1([], _, [], []).
partition_point_1([H|T], Pred_1, Before, After) :-
( call(Pred_1, H)
-> Before = [H|B],
partition_point_1(T, Pred_1, B, After)
; Before = [],
After = [H|T]
).
(мне не нравится это имя, но мы можем жить с ним на данный момент)
Затем:
find_min_4(Min, As) :-
setof(B-A, foo(A, B), [Min-X|Rest]),
partition_point(is_min(Min), [Min-X|Rest], Min_pairs, _),
pairs_values(Min_pairs, As).
is_min(Min, Min-_).
?- find_min_4(Min, As).
Min = 2,
As = [b, e, h].
min_prefix/3
, но в более общем виде. - person   schedule 05.12.2014partition_point
. - person   schedule 05.12.2014