在Prolog中的元组列表中按降序排序

问题描述 投票:0回答:2

我想基于列表的第二个值按降序对元组列表进行排序,而不使用内置的排序谓词。

示例:(Name, Age)

unsorted_list = [(mary, 20), (jack, 50), (bob, 16), (bill, 20) ].

sorted_list = [(jack, 50), (bill, 20), (mary, 20), (bob, 16)].

有谁知道这样做的优雅方式?

list sorting prolog
2个回答
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/3swap_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个规则来处理对:

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
投票

虽然在原始帖子中请求了非内置实现,但我还是想添加@coder发布的评论,如果你使用的是Swi-Prolog,那么很少有额外的排序谓词:predsort/3sort/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)].
© www.soinside.com 2019 - 2024. All rights reserved.