从 Prolog 中的嵌套列表中排序/获取最大成员和 ID?

Sort / get max member and id out of a nested-list in Prolog?

假设我有一些这样的 findall:

findall([ID, Val], (some_predicate(ID, Val), Val >= 50), XS).

这最终出现在列表(或元组?!)的列表中,例如:

[[2, 51], [3, 102], [8, 287], [11, 157]]

如何按值(降序)对列表进行排序?

最后我想得到以下信息:

[Max|RS] = SortedByValue.
Max = [8, 287],
RS = [[11, 157], [3, 102], [2, 51]].

如果您创建一个谓词来转换成对列表中包含两个元素的列表(注意:谓词在两个方向上都起作用),则反转对的顺序

listPairConverter([], []).

listPairConverter([[K, V] | Ti], [V-K | To]) :-
  listPairConverter(Ti, To).

和一个反转列表的谓词

reverseList([], Rl, Rl).

reverseList([H | T], Rl, Acc) :-
  reverseList(T, Rl, [H | Acc]).

使用 iso 谓词 keysort/2,您可以编写一个谓词,根据内部列表的第二个元素对列表进行排序,如下所示

sortValue(Li, Lo) :-
  listPairConverter(Li, R0),
  keysort(R0, R1),
  listPairConverter(R2, R1),
  reverseList(R2, Lo, []).

所以打电话

sortValue([[2, 51], [3, 102], [8, 287], [11, 157]], Lo)

你可以统一 Lo

[[8,287],[11,157],[3,102],[2,51]]

如果你想按值排序,你必须先用 Id 排序吗?如果你不这样做会更容易。 setof/3 将按第一个组件升序排列您的对,然后您可以反转它们:

max_rest(MaxPair, RS) :-
    setof([Val, Id], (some_predicate(Id, Val), Val >= 50), XS),
    reverse(XS, [MaxPair | RS]).

如果您确实需要首先使用 Id 的结果,您可以重新映射它们:

swap([A, B], [B, A]).

max_rest(MaxPair, RS) :-
    setof([Val, Id], (some_predicate(Id, Val), Val >= 50), XValIds),
    maplist(swap, XValIds, XIdVals),
    reverse(XIdVals, [MaxPair | RS]).

你的问题完全符合库(solution_sequences):

?- findall([ID, Val], order_by([desc(Val)], (some_predicate(ID, Val), Val >= 50)), [Max|Rs]).
Max = [8, 287],
Rs = [[11, 157], [3, 102], [2, 51]].

这个库很新,因为我以前从未使用过它,所以我通过以下测试步骤得到了结果:

?- [library(solution_sequences)].
true.

?- [user].
some_predicate(ID,Val) :- member([ID,Val],[[2, 51], [3, 102], [8, 287], [11, 157]]).
|: (^D here)true.

?- order_by([desc(Val)], (some_predicate(ID, Val), Val >= 50)).
Val = 287,
ID = 8 ;
Val = 157,
ID = 11 ;
...