-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Revise sort.md and docstrings in sort.jl #48363
Changes from 2 commits
73cdf43
7c9cbb1
5c14af3
bdf436e
e052d85
db3c429
85b61f6
1514ea5
6c774a6
d70f4d8
d13db49
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,7 +1,7 @@ | ||||||
# Sorting and Related Functions | ||||||
|
||||||
Julia has an extensive, flexible API for sorting and interacting with already-sorted arrays of | ||||||
values. By default, Julia picks reasonable algorithms and sorts in standard ascending order: | ||||||
Julia has an extensive, flexible API for sorting and interacting with already-sorted arrays | ||||||
of values. By default, Julia picks reasonable algorithms and sorts in ascending order: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "standard" is a bit presumptuous imo. I hope what we chose as Julia's standard is also what the user things of as standard, but maybe they are used to seeing big things first. "ascending" is the more useful and unambiguous descriptor here. |
||||||
|
||||||
```jldoctest | ||||||
julia> sort([2,3,1]) | ||||||
|
@@ -11,7 +11,7 @@ julia> sort([2,3,1]) | |||||
3 | ||||||
``` | ||||||
|
||||||
You can easily sort in reverse order as well: | ||||||
You can sort in reverse order as well: | ||||||
|
||||||
```jldoctest | ||||||
julia> sort([2,3,1], rev=true) | ||||||
|
@@ -21,7 +21,8 @@ julia> sort([2,3,1], rev=true) | |||||
1 | ||||||
``` | ||||||
|
||||||
To sort an array in-place, use the "bang" version of the sort function: | ||||||
`sort` constructs a sorted copy leaving its input unchanged. Use the "bang" version of | ||||||
the sort function to mutate an existing array: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
1.8: julia> @btime sort!(x) setup=(x=rand(300)) evals=1;
8.784 μs (0 allocations: 0 bytes)
julia> @btime sort!(x; alg=QuickSort) setup=(x=rand(300)) evals=1;
8.855 μs (0 allocations: 0 bytes)
julia> @btime sort!(x) setup=(x=rand(1:100, 300)) evals=1;
1.363 μs (1 allocation: 896 bytes)
julia> @btime sort!(x; alg=QuickSort) setup=(x=rand(1:100, 300)) evals=1;
1.480 μs (1 allocation: 896 bytes) 1.9: julia> @btime sort!(x) setup=(x=rand(300)) evals=1;
5.661 μs (1 allocation: 2.50 KiB)
julia> @btime sort!(x; alg=QuickSort) setup=(x=rand(300)) evals=1;
8.472 μs (0 allocations: 0 bytes)
julia> @btime sort!(x) setup=(x=rand(1:100, 300)) evals=1;
1.309 μs (1 allocation: 896 bytes)
julia> @btime sort!(x; alg=QuickSort) setup=(x=rand(1:100, 300)) evals=1;
7.965 μs (0 allocations: 0 bytes) |
||||||
|
||||||
```jldoctest | ||||||
julia> a = [2,3,1]; | ||||||
|
@@ -35,8 +36,8 @@ julia> a | |||||
3 | ||||||
``` | ||||||
|
||||||
Instead of directly sorting an array, you can compute a permutation of the array's indices that | ||||||
puts the array into sorted order: | ||||||
Instead of directly sorting an array, you can compute a permutation of the array's | ||||||
indices that puts the array into sorted order: | ||||||
|
||||||
```julia-repl | ||||||
julia> v = randn(5) | ||||||
|
@@ -64,7 +65,7 @@ julia> v[p] | |||||
0.382396 | ||||||
``` | ||||||
|
||||||
Arrays can easily be sorted according to an arbitrary transformation of their values: | ||||||
Arrays can be sorted according to an arbitrary transformation of their values: | ||||||
|
||||||
```julia-repl | ||||||
julia> sort(v, by=abs) | ||||||
|
@@ -100,9 +101,12 @@ julia> sort(v, alg=InsertionSort) | |||||
0.382396 | ||||||
``` | ||||||
|
||||||
All the sorting and order related functions rely on a "less than" relation defining a total order | ||||||
All the sorting and order related functions rely on a "less than" relation defining a | ||||||
[strict weak order](https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings) | ||||||
on the values to be manipulated. The `isless` function is invoked by default, but the relation | ||||||
can be specified via the `lt` keyword. | ||||||
can be specified via the `lt` keyword, a function that takes two array elements and returns true | ||||||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
if and only if the first argument is "less than" the second. See [Alternate orderings](@ref) for | ||||||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
more info. | ||||||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
## Sorting Functions | ||||||
|
||||||
|
@@ -134,88 +138,45 @@ Base.Sort.partialsortperm! | |||||
|
||||||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
## Sorting Algorithms | ||||||
|
||||||
There are currently four sorting algorithms available in base Julia: | ||||||
There are currently four sorting algorithms publicly available in base Julia: | ||||||
|
||||||
* [`InsertionSort`](@ref) | ||||||
* [`QuickSort`](@ref) | ||||||
* [`PartialQuickSort(k)`](@ref) | ||||||
* [`MergeSort`](@ref) | ||||||
|
||||||
`InsertionSort` is an O(n²) stable sorting algorithm. It is efficient for very small `n`, | ||||||
and is used internally by `QuickSort`. | ||||||
By default, the `sort` family of functions uses stable sorting algorithms that are fast | ||||||
on most inputs. The exact algorithm choice is an implementation detail to allow for | ||||||
future performance improvements. Currently, a hybrid of `RadixSort`, `ScratchQuickSort`, | ||||||
`InsertionSort`, and `CountingSort` is used based on input type, size, and composition. | ||||||
Implementation details are subject to change but currently availible in the extended help | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
of `??Base.DEFAULT_STABLE` and the docstrings of internal sorting algorithms listed there. | ||||||
|
||||||
`QuickSort` is a very fast sorting algorithm with an average-case time complexity of | ||||||
O(n log n). `QuickSort` is stable, i.e., elements considered equal will remain in the same | ||||||
order. Notice that O(n²) is worst-case complexity, but it gets vanishingly unlikely as the | ||||||
pivot selection is randomized. | ||||||
|
||||||
`PartialQuickSort(k::OrdinalRange)` is similar to `QuickSort`, but the output array is only | ||||||
sorted in the range of `k`. For example: | ||||||
|
||||||
```jldoctest | ||||||
julia> x = rand(1:500, 100); | ||||||
|
||||||
julia> k = 50:100; | ||||||
|
||||||
julia> s1 = sort(x; alg=QuickSort); | ||||||
|
||||||
julia> s2 = sort(x; alg=PartialQuickSort(k)); | ||||||
|
||||||
julia> map(issorted, (s1, s2)) | ||||||
(true, false) | ||||||
|
||||||
julia> map(x->issorted(x[k]), (s1, s2)) | ||||||
(true, true) | ||||||
|
||||||
julia> s1[k] == s2[k] | ||||||
true | ||||||
``` | ||||||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
!!! compat "Julia 1.9" | ||||||
The `QuickSort` and `PartialQuickSort` algorithms are stable since Julia 1.9. | ||||||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
`MergeSort` is an O(n log n) stable sorting algorithm but is not in-place – it requires a temporary | ||||||
array of half the size of the input array – and is typically not quite as fast as `QuickSort`. | ||||||
It is the default algorithm for non-numeric data. | ||||||
|
||||||
The default sorting algorithms are chosen on the basis that they are fast and stable. | ||||||
Usually, `QuickSort` is selected, but `InsertionSort` is preferred for small data. | ||||||
You can also explicitly specify your preferred algorithm, e.g. | ||||||
`sort!(v, alg=PartialQuickSort(10:20))`. | ||||||
|
||||||
The mechanism by which Julia picks default sorting algorithms is implemented via the | ||||||
`Base.Sort.defalg` function. It allows a particular algorithm to be registered as the | ||||||
default in all sorting functions for specific arrays. For example, here is the default | ||||||
method from [`sort.jl`](https://github.com/JuliaLang/julia/blob/master/base/sort.jl): | ||||||
|
||||||
```julia | ||||||
defalg(v::AbstractArray) = DEFAULT_STABLE | ||||||
``` | ||||||
|
||||||
You may change the default behavior for specific types by defining new methods for `defalg`. | ||||||
You can explicitly specify your preferred algorithm with the `alg` keyword | ||||||
(e.g. `sort!(v, alg=PartialQuickSort(10:20))`) or reconfigure the default sorting algorithm | ||||||
for a custom types by adding a specialized method to the `Base.Sort.defalg` function. | ||||||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
For example, [InlineStrings.jl](https://github.com/JuliaStrings/InlineStrings.jl/blob/v1.3.2/src/InlineStrings.jl#L903) | ||||||
defines the following method: | ||||||
```julia | ||||||
Base.Sort.defalg(::AbstractArray{<:Union{SmallInlineStrings, Missing}}) = InlineStringSort | ||||||
``` | ||||||
|
||||||
!!! compat "Julia 1.9" | ||||||
The default sorting algorithm (returned by `Base.Sort.defalg`) is guaranteed | ||||||
to be stable since Julia 1.9. Previous versions had unstable edge cases when sorting numeric arrays. | ||||||
The default sorting algorithm (returned by `Base.Sort.defalg`) is guaranteed to be stable | ||||||
since Julia 1.9. Previous versions had unstable edge cases when sorting numeric arrays. | ||||||
|
||||||
## 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`. | ||||||
By default, `sort`, `searchsorted`, 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 | ||||||
[strict weak order](https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings). | ||||||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
To be a strict weak order, for any elements `a`, `b`, `c` the following hold: | ||||||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
* `lt(a, b) && lt(b, a) === false`; | ||||||
* if `lt(a, b) && lt(b, c)`, then `lt(a, c)`; and | ||||||
* if `!lt(a, b) && !lt(b, c)`, then `!lt(a, 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. | ||||||
LilithHafner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bug fix. In 1.8 we have
Which
a) returns the whole array and
b) gets the
k
th element right, but does not sort the elements before indexk