Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation for Base.Order module #36886

Merged
merged 3 commits into from
Sep 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

"""
jlumpe marked this conversation as resolved.
Show resolved Hide resolved
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}}

"""
jlumpe marked this conversation as resolved.
Show resolved Hide resolved
Base.Order.Forward

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

"""
jlumpe marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -187,3 +187,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
```