[ Comparing and Sorting | Reference Manual | Alphabetic Index ]

# sort(+Key, +Order, +Random, -Sorted)

Succeeds if Sorted is the sorted list version of Random. The sort is done according to the Key and Order specifications.

Key
  A non-negative integer, or a list of positive integers.
Order
  One of the atoms =<, >=, < or >, possibly prefixed with @ or $.
Random
  List.
Sorted
  List or variable.

## Description

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      retained

The alternative ordering criteria are:

@ standard term order
  The sort is done according to the standard ordering of terms. This can be applied to any term, see compare/3 for the definition. Note in particular that numbers are first ordered by their type (integer, float, etc) and only then by their magnitude, i.e. sorting numbers of different types may not give the expected result.
$ numeric order
  The sort is done according to numeric order. The sorting keys must all be numbers, but can be a mix of numeric types. They are compared in the way they are compared by the arithmetic comparisons (</2, <=/2, etc). Unlike standard order, this will consider numbers such as 3 and 3.0 as equal, and -0.0 as equal to 0.0.

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):

1. First, sort according to the least important key. Sort the result by the next more important key, and so on. Thanks to the stability of sort/4, the ordering of the less important keys is preserved as required.
2. For each list element, construct a compound key from the individual keys, and pair each new key with its list element. Sort the keyed list, then strip the auxiliary keys.

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.

### Modes and Determinism

- sort(+, +, +, -) is det

### Exceptions

(4) instantiation fault
  Random is a partial list
(4) instantiation fault
  Numeric order is selected, but Random contains variables
(5) type error
  Key is greater than 0, and not all of Random's elements are compound terms.
(5) type error
  Numeric order is selected, but Random contains non-numeric elements.
(5) type error
  Key is not an integer or a list of integers.
(6) out of range
  One of the compound terms in Random has not got as many as Key arguments.
(20) arithmetic exception
  Random has elements whose numerical order is undefined.

## Examples

    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).

## See Also

compare / 3, msort / 2, sort / 2, number_sort / 2, keysort / 2, array_sort / 4