我想基于列表的第二个值按降序对元组列表进行排序,而不使用内置的排序谓词。
示例:(Name, Age)
。
unsorted_list = [(mary, 20), (jack, 50), (bob, 16), (bill, 20) ].
sorted_list = [(jack, 50), (bill, 20), (mary, 20), (bob, 16)].
有谁知道这样做的优雅方式?
答案 0 :(得分:7)
有很多方法可以实现这一点。一种方法是从头开始实现您的自定义对排序,这样做的好处是您可以确切地知道算法的实现,从而确保复杂性,但这可能不是那么优雅。
另一个更优雅的方法是使用Prolog的ISO谓词 keysort/2
,它对[X1-Y1, X2-Y2, ...]
形式的对的列表进行排序,并且排序基于第一个参数对(Xi
)。因此,您需要更改[-20-mary, -50-jack, -16-bob, -20-bill]
格式的列表,然后应用keysort/2
。请注意,由于@ false的注释为了实现降序的稳定解决方案,我们可以否定数字并按升序排序否定数字:
:-use_module(library(clpfd)).
swap_internals((X,Y), Y1-X):- Y1 #= -Y.
pair_sort(L,Sorted):-
maplist(swap_internals, L, L2),
keysort(L2, L3),
maplist(swap_internals, Sorted, L3).
在上文中,您使用maplist/3
和swap_internals/2
以适当的形式构建列表,并使用keysort/2
对其进行排序,然后再次使用maplist/3
进行更改。
示例:
?- pair_sort([(mary, 20), (jack, 50), (bob, 16), (bill, 20) ],L).
L = [(jack, 50), (bill, 20), (mary, 20), (bob, 16)].
这是降序的另一种方式,只需使用 sort/4
谓词:
sort(2, @>=, L, Sorted).
示例:
?- sort(2,@>=, [(mary, 20), (jack, 50), (bob, 16), (bill, 20) ], L).
L = [(jack, 50), (mary, 20), (bill, 20), (bob, 16)].
虽然它不是ISO谓词,但这种方式显然更容易。
我没有看到“不使用内置排序谓词”部分问题,因此您可以编写一个典型的合并排序来更改下面merge/2
的第3个规则以处理对:< / p>
halve([], [], []).
halve([A], [A], []).
halve([A,B|Cs], [A|X], [B|Y]) :- halve(Cs, X, Y).
merge([], Ys, Ys).
merge(Xs, [], Xs).
merge([(X1,X2)|Xs], [(Y1,Y2)|Ys], M) :-
(
X2 > Y2 -> M = [(X1,X2)|Ms], merge(Xs, [(Y1,Y2)|Ys], Ms)
; M = [(Y1,Y2)|Ms], merge([(X1,X2)|Xs], Ys, Ms)
).
mergeSort([], []).
mergeSort([E], [E]).
mergeSort([E1,E2|Es], SL) :-
halve([E1,E2|Es], L1, L2),
mergeSort(L1, SL1),
mergeSort(L2, SL2),
merge(SL1, SL2, SL).
示例:
?- mergeSort([(mary, 20), (jack, 50), (bob, 16), (bill, 20) ],L).
L = [(jack, 50), (bill, 20), (mary, 20), (bob, 16)] ;
false.
答案 1 :(得分:1)
虽然在原始帖子中请求了非内置实现,但我还是想添加@coder发布的评论,如果你使用的是Swi-Prolog,那么很少有额外的排序谓词:predsort/3
和sort/4
predsort/3
特别有意义,因为它允许您指定自定义排序谓词:
compare_tuples_descending('<', (_, X), (_, Y)) :- X > Y, !.
compare_tuples_descending('>', _, _).
sort_tuples_descending(Unsorted, Sorted) :-
predsort(compare_tuples_descending, Unsorted, Sorted).
用法示例:
?- sort_tuples_descending([(mary, 20), (jack, 50), (bob, 16), (bill, 20)], S).
S = [(jack, 50), (bill, 20), (mary, 20), (bob, 16)].