从 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 ;
...
假设我有一些这样的 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 ;
...