Generic sorting primitive: sorts the list Random according to the Key and Order specifications, and unifies Sorted with the result. The sort is stable, i.e. the order of elements with equal keys is preserved.
The Key argument determines which part of the list elements is considered the sorting key. If Key is 0, then the entire term is taken as the sorting key (in this case, the list can contain anything, including numbers, atoms, strings, compound terms, and even variables). If Key is a positive integer (or a list of those), then the list elements will get ordered by their Keyth subterm (in this case, the list must contain compound terms with appropriate subterms).
The Order argument specifies whether to use standard term order (@) or numeric order ($), whether the list is sorted into ascending (<, =<) or descending (>, >=) order, and whether duplicates are to be retained (=<, >=) or removed (<, >). The way to remember the Order argument is that it is the relation which holds between adjacent elements in the result.
Order ordering direction duplicates --------------------------------------------------------------- @< (or <) standard ascending removed @=< (or =<) standard ascending retained @> (or >) standard descending removed @>= (or >=) standard descending retained $< numeric ascending removed $=< numeric ascending retained $> numeric descending removed $>= numeric descending retainedThe alternative ordering criteria are:
The other sorting primitives may be defined in terms of sort/4 as follows:
sort(Random, Sorted) :- sort(0, @<, Random, Sorted). msort(Random, Sorted) :- sort(0, @=<, Random, Sorted). keysort(Random, Sorted) :- sort(1, @=<, Random, Sorted). number_sort(Random, Sorted) :- sort(0, $=<, Random, Sorted).Sorting with _multiple_ keys can be done in one of two ways (see examples):
The _algorithm_ used is natural merge sort. This implies a worst case complexity of N*ld(N), but many special cases will be sorted significantly faster. For instance, pre-sorted, reverse-sorted, and the concatenation of two sorted lists will all be sorted in linear time.
NOTE regarding sorting bounded reals: While the standard ordering treats a bounded real as a compound term and orders them by lower bound and then upper bound, numerical ordering treats them as true intervals. As a consequence the order of overlapping intervals is undefined: 1.0__1.1 @< 1.0__1.2 while no numerical order is defined. In such cases an arithmetic exception is thrown. This can have unexpected consequences: care must be taken when sorting a list containing both rationals and bounded reals. While integers and floats are converted to zero-width intervals for the purposes of comparison, rationals are converted to small intervals guaranteed to contain the rational, e.g X is breal(1_1) gives X=0.99999999999999989__1.0000000000000002 and thus no order is defined between 1_1 and 1.0__1.0.
Success: sort(0, <, [], S). (gives S=[]). sort(0, <, [3,1,6,7,2], S). (gives S=[1,2,3,6,7]). sort(0, >, [q,1,3,a,e,N], S). (gives N=_g78,S=[q,e,a,3,1,_g78]). sort(0,=<, [1,3,2,3,4,1], S). (gives S=[1,1,2,3,3,4]). sort(2, <, [f(1,3),h(2,1)], S). (gives S=[h(2,1),f(1,3)]). sort(1, <, [f(1,3),h(2,1)], S). (gives S=[f(1,3),h(2,1)]). sort([2,1],=<,[f(3,a(2)),f(1,a(1)),f(0,a(3)),f(1,a(4))],S). (gives S=[f(1,a(1)),f(3,a(2)),f(0,a(3)),f(1,a(4))]). % standard vs numeric order sort(0, @<, [1,2,3,2.0,3], S). (gives S = [2.0, 1, 2, 3]) sort(0, $<, [1,2,3,2.0,3], S). (gives S = [1, 2, 3]) sort(0,@=<, [1,2,3,2.0,3], S). (gives S = [2.0, 1, 2, 3, 3]) sort(0,$=<, [1,2,3,2.0,3], S). (gives S = [1, 2, 2.0, 3, 3]) sort(0,@=<, [1,1.0,1_1], S). (gives S = [1.0, 1_1, 1]) sort(0,$=<, [1,1.0,1_1], S). (gives S = [1, 1.0, 1_1]) sort(0, @<, [1,1.0,1_1], S). (gives S = [1.0, 1_1, 1]) sort(0, $<, [1,1.0,1_1], S). (gives S = [1]) sort(0, $<, [1.0,1,1_1], S). (gives S = [1.0]) sort(0, $<, [1_1,1.0,1], S). (gives S = [1_1]) % Sort according to argument 3 (major) and 2 (minor) - method 1 ?- S = [t(ok,a,2), t(good,b,1), t(best,a,1)], sort(2, =<, S, S2), % sort less important key first sort(3, =<, S2, S32). % sort more important key last S2 = [t(ok,a,2), t(best,a,1), t(good,b,1)] S32 = [t(best,a,1), t(good,b,1), t(ok,a,2)] Yes (0.00s cpu) % Sort according to argument 3 (major) and 2 (minor) - method 2 ?- S = [t(ok,a,2), t(good,b,1), t(best,a,1)], ( foreach(T,S),foreach(K-T,KTs) do T=t(_,B,C), K=key(C,B) ), sort(1, =<, KTs, SKTs), % same as keysort(KTs, SKTs) ( foreach(_-T,SKTs), foreach(T,S32) do true ). KTs = [key(2,a)-t(ok,a,2), key(1,b)-t(good,b,1), key(1,a)-t(best,a,1)] SKTs = [key(1,a)-t(best,a,1), key(1,b)-t(good,b,1), key(2,a)-t(ok,a,2)] S32 = [t(best,a,1), t(good,b,1), t(ok,a,2)] Yes (0.00s cpu) Error: sort(0, <, [](5,3,7), S). (Error 5). sort(1, <, [f(1),f(3),5], S). (Error 5). sort(1, <, [f(1),f(3),5], S). (Error 5). sort(1.0, <, [f(1),f(3),f(5)], S). (Error 5). sort(2, <, [f(1,2),g(3,a),f(5)], S). (Error 6). sort(0, $<, [1,two,3], S). (Error 5). sort(0, $<, [1.0__1.1,1.0__1.1], S). (Error 20).