Skip to content

Commit

Permalink
Add documentation for Base.Order module (JuliaLang#36886)
Browse files Browse the repository at this point in the history
* Add docstrings for Base.Order module
* Add documentation section for Base.Order
* Add reference to documentation on Base.Order in isless() docstring
  • Loading branch information
jlumpe committed Sep 29, 2020
1 parent 112f7a1 commit be54a6c
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
2 changes: 2 additions & 0 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ This is the default comparison used by [`sort`](@ref).
Non-numeric types with a total order should implement this function.
Numeric types only need to implement it if they have special values such as `NaN`.
Types with a partial order should implement [`<`](@ref).
See the documentation on [Alternate orderings](@ref) for how to define alternate
ordering methods that can be used in sorting and related functions.
# Examples
```jldoctest
Expand Down
68 changes: 68 additions & 0 deletions base/ordering.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,26 @@ export # not exported by Base
DirectOrdering,
lt, ord, ordtype

"""
Base.Order.Ordering
Abstract type which represents a total order on some set of elements.
Use [`Base.Order.lt`](@ref) to compare two elements according to the ordering.
"""
abstract type Ordering end

struct ForwardOrdering <: Ordering end

"""
ReverseOrdering(fwd::Ordering=Forward)
A wrapper which reverses an ordering.
For a given `Ordering` `o`, the following holds for all `a`, `b`:
lt(ReverseOrdering(o), a, b) == lt(o, b, a)
"""
struct ReverseOrdering{Fwd<:Ordering} <: Ordering
fwd::Fwd
end
Expand All @@ -31,9 +48,26 @@ ReverseOrdering() = ReverseOrdering(ForwardOrdering())

const DirectOrdering = Union{ForwardOrdering,ReverseOrdering{ForwardOrdering}}

"""
Base.Order.Forward
Default ordering according to [`isless`](@ref).
"""
const Forward = ForwardOrdering()

"""
Base.Order.Reverse
Reverse ordering according to [`isless`](@ref).
"""
const Reverse = ReverseOrdering()

"""
By(by, order::Ordering=Forward)
`Ordering` which applies `order` to elements after they have been transformed
by the function `by`.
"""
struct By{T, O} <: Ordering
by::T
order::O
Expand All @@ -42,10 +76,23 @@ end
# backwards compatibility with VERSION < v"1.5-"
By(by) = By(by, Forward)

"""
Lt(lt)
`Ordering` which calls `lt(a, b)` to compare elements. `lt` should
obey the same rules as implementations of [`isless`](@ref).
"""
struct Lt{T} <: Ordering
lt::T
end

"""
Perm(order::Ordering, data::AbstractVector)
`Ordering` on the indices of `data` where `i` is less than `j` if `data[i]` is
less than `data[j]` according to `order`. In the case that `data[i]` and
`data[j]` are equal, `i` and `j` are compared by numeric value.
"""
struct Perm{O<:Ordering,V<:AbstractVector} <: Ordering
order::O
data::V
Expand All @@ -54,6 +101,11 @@ end
ReverseOrdering(by::By) = By(by.by, ReverseOrdering(by.order))
ReverseOrdering(perm::Perm) = Perm(ReverseOrdering(perm.order), perm.data)

"""
lt(o::Ordering, a, b)
Test whether `a` is less than `b` according to the ordering `o`.
"""
lt(o::ForwardOrdering, a, b) = isless(a,b)
lt(o::ReverseOrdering, a, b) = lt(o.fwd,b,a)
lt(o::By, a, b) = lt(o.order,o.by(a),o.by(b))
Expand All @@ -78,6 +130,22 @@ function _ord(lt, by, order::Ordering)
end
end

"""
ord(lt, by, rev::Union{Bool, Nothing}, order::Ordering=Forward)
Construct an [`Ordering`](@ref) object from the same arguments used by
[`sort!`](@ref).
Elements are first transformed by the function `by` (which may be
[`identity`](@ref)) and are then compared according to either the function `lt`
or an existing ordering `order`. `lt` should be [`isless`](@ref) or a function
which obeys similar rules. Finally, the resulting order is reversed if
`rev=true`.
Passing an `lt` other than `isless` along with an `order` other than
[`Base.Order.Forward`](@ref) or [`Base.Order.Reverse`](@ref) is not permitted,
otherwise all options are independent and can be used together in all possible
combinations.
"""
ord(lt, by, rev::Nothing, order::Ordering=Forward) = _ord(lt, by, order)

function ord(lt, by, rev::Bool, order::Ordering=Forward)
Expand Down
29 changes: 29 additions & 0 deletions doc/src/base/sort.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,32 @@ defalg(v::AbstractArray{<:Number}) = QuickSort
As for numeric arrays, choosing a non-stable default algorithm for array types for which the notion
of a stable sort is meaningless (i.e. when two values comparing equal can not be distinguished)
may make sense.

## Alternate orderings

By default, `sort` and related functions use [`isless`](@ref) to compare two
elements in order to determine which should come first. The
[`Base.Order.Ordering`](@ref) abstract type provides a mechanism for defining
alternate orderings on the same set of elements. Instances of `Ordering` define
a [total order](https://en.wikipedia.org/wiki/Total_order) on a set of elements,
so that for any elements `a`, `b`, `c` the following hold:

* Exactly one of the following is true: `a` is less than `b`, `b` is less than
`a`, or `a` and `b` are equal (according to [`isequal`](@ref)).
* The relation is transitive - if `a` is less than `b` and `b` is less than `c`
then `a` is less than `c`.

The [`Base.Order.lt`](@ref) function works as a generalization of `isless` to
test whether `a` is less than `b` according to a given order.

```@docs
Base.Order.Ordering
Base.Order.lt
Base.Order.ord
Base.Order.Forward
Base.Order.ReverseOrdering
Base.Order.Reverse
Base.Order.By
Base.Order.Lt
Base.Order.Perm
```

0 comments on commit be54a6c

Please sign in to comment.