fix incorrect folder name for julia-0.6.x
Former-commit-id: ef2c7401e0876f22d2f7762d182cfbcd5a7d9c70
This commit is contained in:
931
julia-0.6.3/share/julia/base/sort.jl
Normal file
931
julia-0.6.3/share/julia/base/sort.jl
Normal file
@@ -0,0 +1,931 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module Sort
|
||||
|
||||
using Base: Order, Checked, copymutable, linearindices, IndexStyle, viewindexing, IndexLinear, _length
|
||||
|
||||
import
|
||||
Base.sort,
|
||||
Base.sort!,
|
||||
Base.issorted,
|
||||
Base.sortperm,
|
||||
Base.Slice,
|
||||
Base.to_indices
|
||||
|
||||
export # also exported by Base
|
||||
# order-only:
|
||||
issorted,
|
||||
select,
|
||||
select!,
|
||||
searchsorted,
|
||||
searchsortedfirst,
|
||||
searchsortedlast,
|
||||
# order & algorithm:
|
||||
sort,
|
||||
sort!,
|
||||
selectperm,
|
||||
selectperm!,
|
||||
sortperm,
|
||||
sortperm!,
|
||||
sortrows,
|
||||
sortcols,
|
||||
# algorithms:
|
||||
InsertionSort,
|
||||
QuickSort,
|
||||
MergeSort,
|
||||
PartialQuickSort
|
||||
|
||||
export # not exported by Base
|
||||
Algorithm,
|
||||
DEFAULT_UNSTABLE,
|
||||
DEFAULT_STABLE,
|
||||
SMALL_ALGORITHM,
|
||||
SMALL_THRESHOLD
|
||||
|
||||
|
||||
## functions requiring only ordering ##
|
||||
|
||||
function issorted(itr, order::Ordering)
|
||||
state = start(itr)
|
||||
done(itr,state) && return true
|
||||
prev, state = next(itr, state)
|
||||
while !done(itr, state)
|
||||
this, state = next(itr, state)
|
||||
lt(order, this, prev) && return false
|
||||
prev = this
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
"""
|
||||
issorted(v, lt=isless, by=identity, rev:Bool=false, order::Ordering=Forward)
|
||||
|
||||
Test whether a vector is in sorted order. The `lt`, `by` and `rev` keywords modify what
|
||||
order is considered to be sorted just as they do for [`sort`](@ref).
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> issorted([1, 2, 3])
|
||||
true
|
||||
|
||||
julia> issorted([(1, "b"), (2, "a")], by = x -> x[1])
|
||||
true
|
||||
|
||||
julia> issorted([(1, "b"), (2, "a")], by = x -> x[2])
|
||||
false
|
||||
|
||||
julia> issorted([(1, "b"), (2, "a")], by = x -> x[2], rev=true)
|
||||
true
|
||||
```
|
||||
"""
|
||||
issorted(itr;
|
||||
lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward) =
|
||||
issorted(itr, ord(lt,by,rev,order))
|
||||
|
||||
function select!(v::AbstractVector, k::Union{Int,OrdinalRange}, o::Ordering)
|
||||
inds = indices(v, 1)
|
||||
sort!(v, first(inds), last(inds), PartialQuickSort(k), o)
|
||||
v[k]
|
||||
end
|
||||
select!(v::AbstractVector, k::Union{Int,OrdinalRange};
|
||||
lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward) =
|
||||
select!(v, k, ord(lt,by,rev,order))
|
||||
|
||||
select(v::AbstractVector, k::Union{Int,OrdinalRange}; kws...) = select!(copymutable(v), k; kws...)
|
||||
|
||||
|
||||
# reference on sorted binary search:
|
||||
# http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary
|
||||
|
||||
# index of the first value of vector a that is greater than or equal to x;
|
||||
# returns length(v)+1 if x is greater than all values in v.
|
||||
function searchsortedfirst(v::AbstractVector, x, lo::Int, hi::Int, o::Ordering)
|
||||
lo = lo-1
|
||||
hi = hi+1
|
||||
@inbounds while lo < hi-1
|
||||
m = (lo+hi)>>>1
|
||||
if lt(o, v[m], x)
|
||||
lo = m
|
||||
else
|
||||
hi = m
|
||||
end
|
||||
end
|
||||
return hi
|
||||
end
|
||||
|
||||
# index of the last value of vector a that is less than or equal to x;
|
||||
# returns 0 if x is less than all values of v.
|
||||
function searchsortedlast(v::AbstractVector, x, lo::Int, hi::Int, o::Ordering)
|
||||
lo = lo-1
|
||||
hi = hi+1
|
||||
@inbounds while lo < hi-1
|
||||
m = (lo+hi)>>>1
|
||||
if lt(o, x, v[m])
|
||||
hi = m
|
||||
else
|
||||
lo = m
|
||||
end
|
||||
end
|
||||
return lo
|
||||
end
|
||||
|
||||
# returns the range of indices of v equal to x
|
||||
# if v does not contain x, returns a 0-length range
|
||||
# indicating the insertion point of x
|
||||
function searchsorted(v::AbstractVector, x, ilo::Int, ihi::Int, o::Ordering)
|
||||
lo = ilo-1
|
||||
hi = ihi+1
|
||||
@inbounds while lo < hi-1
|
||||
m = (lo+hi)>>>1
|
||||
if lt(o, v[m], x)
|
||||
lo = m
|
||||
elseif lt(o, x, v[m])
|
||||
hi = m
|
||||
else
|
||||
a = searchsortedfirst(v, x, max(lo,ilo), m, o)
|
||||
b = searchsortedlast(v, x, m, min(hi,ihi), o)
|
||||
return a : b
|
||||
end
|
||||
end
|
||||
return (lo + 1) : (hi - 1)
|
||||
end
|
||||
|
||||
function searchsortedlast(a::Range{<:Real}, x::Real, o::DirectOrdering)
|
||||
if step(a) == 0
|
||||
lt(o, x, first(a)) ? 0 : length(a)
|
||||
else
|
||||
n = round(Integer, clamp((x - first(a)) / step(a) + 1, 1, length(a)))
|
||||
lt(o, x, a[n]) ? n - 1 : n
|
||||
end
|
||||
end
|
||||
|
||||
function searchsortedfirst(a::Range{<:Real}, x::Real, o::DirectOrdering)
|
||||
if step(a) == 0
|
||||
lt(o, first(a), x) ? length(a) + 1 : 1
|
||||
else
|
||||
n = round(Integer, clamp((x - first(a)) / step(a) + 1, 1, length(a)))
|
||||
lt(o, a[n] ,x) ? n + 1 : n
|
||||
end
|
||||
end
|
||||
|
||||
function searchsortedlast(a::Range{<:Integer}, x::Real, o::DirectOrdering)
|
||||
if step(a) == 0
|
||||
lt(o, x, first(a)) ? 0 : length(a)
|
||||
else
|
||||
clamp( fld(floor(Integer, x) - first(a), step(a)) + 1, 0, length(a))
|
||||
end
|
||||
end
|
||||
|
||||
function searchsortedfirst(a::Range{<:Integer}, x::Real, o::DirectOrdering)
|
||||
if step(a) == 0
|
||||
lt(o, first(a), x) ? length(a)+1 : 1
|
||||
else
|
||||
clamp(-fld(floor(Integer, -x) + first(a), step(a)) + 1, 1, length(a) + 1)
|
||||
end
|
||||
end
|
||||
|
||||
function searchsortedfirst(a::Range{<:Integer}, x::Unsigned, o::DirectOrdering)
|
||||
if lt(o, first(a), x)
|
||||
if step(a) == 0
|
||||
length(a) + 1
|
||||
else
|
||||
min(cld(x - first(a), step(a)), length(a)) + 1
|
||||
end
|
||||
else
|
||||
1
|
||||
end
|
||||
end
|
||||
|
||||
function searchsortedlast(a::Range{<:Integer}, x::Unsigned, o::DirectOrdering)
|
||||
if lt(o, x, first(a))
|
||||
0
|
||||
elseif step(a) == 0
|
||||
length(a)
|
||||
else
|
||||
min(fld(x - first(a), step(a)) + 1, length(a))
|
||||
end
|
||||
end
|
||||
|
||||
searchsorted(a::Range{<:Real}, x::Real, o::DirectOrdering) =
|
||||
searchsortedfirst(a, x, o) : searchsortedlast(a, x, o)
|
||||
|
||||
for s in [:searchsortedfirst, :searchsortedlast, :searchsorted]
|
||||
@eval begin
|
||||
$s(v::AbstractVector, x, o::Ordering) = (inds = indices(v, 1); $s(v,x,first(inds),last(inds),o))
|
||||
$s(v::AbstractVector, x;
|
||||
lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward) =
|
||||
$s(v,x,ord(lt,by,rev,order))
|
||||
$s(v::AbstractVector, x) = $s(v, x, Forward)
|
||||
end
|
||||
end
|
||||
|
||||
## sorting algorithms ##
|
||||
|
||||
abstract type Algorithm end
|
||||
|
||||
struct InsertionSortAlg <: Algorithm end
|
||||
struct QuickSortAlg <: Algorithm end
|
||||
struct MergeSortAlg <: Algorithm end
|
||||
|
||||
struct PartialQuickSort{T <: Union{Int,OrdinalRange}} <: Algorithm
|
||||
k::T
|
||||
end
|
||||
|
||||
Base.first(a::PartialQuickSort{Int}) = 1
|
||||
Base.last(a::PartialQuickSort{Int}) = a.k
|
||||
Base.first(a::PartialQuickSort) = first(a.k)
|
||||
Base.last(a::PartialQuickSort) = last(a.k)
|
||||
|
||||
const InsertionSort = InsertionSortAlg()
|
||||
const QuickSort = QuickSortAlg()
|
||||
const MergeSort = MergeSortAlg()
|
||||
|
||||
const DEFAULT_UNSTABLE = QuickSort
|
||||
const DEFAULT_STABLE = MergeSort
|
||||
const SMALL_ALGORITHM = InsertionSort
|
||||
const SMALL_THRESHOLD = 20
|
||||
|
||||
function sort!(v::AbstractVector, lo::Int, hi::Int, ::InsertionSortAlg, o::Ordering)
|
||||
@inbounds for i = lo+1:hi
|
||||
j = i
|
||||
x = v[i]
|
||||
while j > lo
|
||||
if lt(o, x, v[j-1])
|
||||
v[j] = v[j-1]
|
||||
j -= 1
|
||||
continue
|
||||
end
|
||||
break
|
||||
end
|
||||
v[j] = x
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
# selectpivot!
|
||||
#
|
||||
# Given 3 locations in an array (lo, mi, and hi), sort v[lo], v[mi], v[hi]) and
|
||||
# choose the middle value as a pivot
|
||||
#
|
||||
# Upon return, the pivot is in v[lo], and v[hi] is guaranteed to be
|
||||
# greater than the pivot
|
||||
|
||||
@inline function selectpivot!(v::AbstractVector, lo::Int, hi::Int, o::Ordering)
|
||||
@inbounds begin
|
||||
mi = (lo+hi)>>>1
|
||||
|
||||
# sort the values in v[lo], v[mi], v[hi]
|
||||
|
||||
if lt(o, v[mi], v[lo])
|
||||
v[mi], v[lo] = v[lo], v[mi]
|
||||
end
|
||||
if lt(o, v[hi], v[mi])
|
||||
if lt(o, v[hi], v[lo])
|
||||
v[lo], v[mi], v[hi] = v[hi], v[lo], v[mi]
|
||||
else
|
||||
v[hi], v[mi] = v[mi], v[hi]
|
||||
end
|
||||
end
|
||||
|
||||
# move v[mi] to v[lo] and use it as the pivot
|
||||
v[lo], v[mi] = v[mi], v[lo]
|
||||
pivot = v[lo]
|
||||
end
|
||||
|
||||
# return the pivot
|
||||
return pivot
|
||||
end
|
||||
|
||||
# partition!
|
||||
#
|
||||
# select a pivot, and partition v according to the pivot
|
||||
|
||||
function partition!(v::AbstractVector, lo::Int, hi::Int, o::Ordering)
|
||||
pivot = selectpivot!(v, lo, hi, o)
|
||||
# pivot == v[lo], v[hi] > pivot
|
||||
i, j = lo, hi
|
||||
@inbounds while true
|
||||
i += 1; j -= 1
|
||||
while lt(o, v[i], pivot); i += 1; end;
|
||||
while lt(o, pivot, v[j]); j -= 1; end;
|
||||
i >= j && break
|
||||
v[i], v[j] = v[j], v[i]
|
||||
end
|
||||
v[j], v[lo] = pivot, v[j]
|
||||
|
||||
# v[j] == pivot
|
||||
# v[k] >= pivot for k > j
|
||||
# v[i] <= pivot for i < j
|
||||
return j
|
||||
end
|
||||
|
||||
function sort!(v::AbstractVector, lo::Int, hi::Int, a::QuickSortAlg, o::Ordering)
|
||||
@inbounds while lo < hi
|
||||
hi-lo <= SMALL_THRESHOLD && return sort!(v, lo, hi, SMALL_ALGORITHM, o)
|
||||
j = partition!(v, lo, hi, o)
|
||||
if j-lo < hi-j
|
||||
# recurse on the smaller chunk
|
||||
# this is necessary to preserve O(log(n))
|
||||
# stack space in the worst case (rather than O(n))
|
||||
lo < (j-1) && sort!(v, lo, j-1, a, o)
|
||||
lo = j+1
|
||||
else
|
||||
j+1 < hi && sort!(v, j+1, hi, a, o)
|
||||
hi = j-1
|
||||
end
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
function sort!(v::AbstractVector, lo::Int, hi::Int, a::MergeSortAlg, o::Ordering, t=similar(v,0))
|
||||
@inbounds if lo < hi
|
||||
hi-lo <= SMALL_THRESHOLD && return sort!(v, lo, hi, SMALL_ALGORITHM, o)
|
||||
|
||||
m = (lo+hi)>>>1
|
||||
(length(t) < m-lo+1) && resize!(t, m-lo+1)
|
||||
|
||||
sort!(v, lo, m, a, o, t)
|
||||
sort!(v, m+1, hi, a, o, t)
|
||||
|
||||
i, j = 1, lo
|
||||
while j <= m
|
||||
t[i] = v[j]
|
||||
i += 1
|
||||
j += 1
|
||||
end
|
||||
|
||||
i, k = 1, lo
|
||||
while k < j <= hi
|
||||
if lt(o, v[j], t[i])
|
||||
v[k] = v[j]
|
||||
j += 1
|
||||
else
|
||||
v[k] = t[i]
|
||||
i += 1
|
||||
end
|
||||
k += 1
|
||||
end
|
||||
while k < j
|
||||
v[k] = t[i]
|
||||
k += 1
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
|
||||
return v
|
||||
end
|
||||
|
||||
## TODO: When PartialQuickSort is parameterized by an Int, this version of sort
|
||||
## has one less comparison per loop than the version below, but enabling
|
||||
## it causes return type inference to fail for sort/sort! (#12833)
|
||||
##
|
||||
# function sort!(v::AbstractVector, lo::Int, hi::Int, a::PartialQuickSort{Int},
|
||||
# o::Ordering)
|
||||
# @inbounds while lo < hi
|
||||
# hi-lo <= SMALL_THRESHOLD && return sort!(v, lo, hi, SMALL_ALGORITHM, o)
|
||||
# j = partition!(v, lo, hi, o)
|
||||
# if j >= a.k
|
||||
# # we don't need to sort anything bigger than j
|
||||
# hi = j-1
|
||||
# elseif j-lo < hi-j
|
||||
# # recurse on the smaller chunk
|
||||
# # this is necessary to preserve O(log(n))
|
||||
# # stack space in the worst case (rather than O(n))
|
||||
# lo < (j-1) && sort!(v, lo, j-1, a, o)
|
||||
# lo = j+1
|
||||
# else
|
||||
# (j+1) < hi && sort!(v, j+1, hi, a, o)
|
||||
# hi = j-1
|
||||
# end
|
||||
# end
|
||||
# return v
|
||||
# end
|
||||
|
||||
|
||||
function sort!(v::AbstractVector, lo::Int, hi::Int, a::PartialQuickSort,
|
||||
o::Ordering)
|
||||
@inbounds while lo < hi
|
||||
hi-lo <= SMALL_THRESHOLD && return sort!(v, lo, hi, SMALL_ALGORITHM, o)
|
||||
j = partition!(v, lo, hi, o)
|
||||
|
||||
if j <= first(a)
|
||||
lo = j+1
|
||||
elseif j >= last(a)
|
||||
hi = j-1
|
||||
else
|
||||
if j-lo < hi-j
|
||||
lo < (j-1) && sort!(v, lo, j-1, a, o)
|
||||
lo = j+1
|
||||
else
|
||||
hi > (j+1) && sort!(v, j+1, hi, a, o)
|
||||
hi = j-1
|
||||
end
|
||||
end
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
## generic sorting methods ##
|
||||
|
||||
defalg(v::AbstractArray) = DEFAULT_STABLE
|
||||
defalg(v::AbstractArray{<:Number}) = DEFAULT_UNSTABLE
|
||||
|
||||
function sort!(v::AbstractVector, alg::Algorithm, order::Ordering)
|
||||
inds = indices(v,1)
|
||||
sort!(v,first(inds),last(inds),alg,order)
|
||||
end
|
||||
|
||||
"""
|
||||
sort!(v; alg::Algorithm=defalg(v), lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)
|
||||
|
||||
Sort the vector `v` in place. `QuickSort` is used by default for numeric arrays while
|
||||
`MergeSort` is used for other arrays. You can specify an algorithm to use via the `alg`
|
||||
keyword (see Sorting Algorithms for available algorithms). The `by` keyword lets you provide
|
||||
a function that will be applied to each element before comparison; the `lt` keyword allows
|
||||
providing a custom "less than" function; use `rev=true` to reverse the sorting order. These
|
||||
options are independent and can be used together in all possible combinations: if both `by`
|
||||
and `lt` are specified, the `lt` function is applied to the result of the `by` function;
|
||||
`rev=true` reverses whatever ordering specified via the `by` and `lt` keywords.
|
||||
|
||||
# Examples
|
||||
|
||||
```jldoctest
|
||||
julia> v = [3, 1, 2]; sort!(v); v
|
||||
3-element Array{Int64,1}:
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
julia> v = [3, 1, 2]; sort!(v, rev = true); v
|
||||
3-element Array{Int64,1}:
|
||||
3
|
||||
2
|
||||
1
|
||||
|
||||
julia> v = [(1, "c"), (3, "a"), (2, "b")]; sort!(v, by = x -> x[1]); v
|
||||
3-element Array{Tuple{Int64,String},1}:
|
||||
(1, "c")
|
||||
(2, "b")
|
||||
(3, "a")
|
||||
|
||||
julia> v = [(1, "c"), (3, "a"), (2, "b")]; sort!(v, by = x -> x[2]); v
|
||||
3-element Array{Tuple{Int64,String},1}:
|
||||
(3, "a")
|
||||
(2, "b")
|
||||
(1, "c")
|
||||
```
|
||||
"""
|
||||
function sort!(v::AbstractVector;
|
||||
alg::Algorithm=defalg(v),
|
||||
lt=isless,
|
||||
by=identity,
|
||||
rev::Bool=false,
|
||||
order::Ordering=Forward)
|
||||
ordr = ord(lt,by,rev,order)
|
||||
if ordr === Forward && isa(v,Vector) && eltype(v)<:Integer
|
||||
n = _length(v)
|
||||
if n > 1
|
||||
min, max = extrema(v)
|
||||
(diff, o1) = sub_with_overflow(max, min)
|
||||
(rangelen, o2) = add_with_overflow(diff, oneunit(diff))
|
||||
if !o1 && !o2 && rangelen < div(n,2)
|
||||
return sort_int_range!(v, rangelen, min)
|
||||
end
|
||||
end
|
||||
end
|
||||
sort!(v, alg, ordr)
|
||||
end
|
||||
|
||||
# sort! for vectors of few unique integers
|
||||
function sort_int_range!(x::Vector{<:Integer}, rangelen, minval)
|
||||
offs = 1 - minval
|
||||
n = length(x)
|
||||
|
||||
where = fill(0, rangelen)
|
||||
@inbounds for i = 1:n
|
||||
where[x[i] + offs] += 1
|
||||
end
|
||||
|
||||
idx = 1
|
||||
@inbounds for i = 1:rangelen
|
||||
lastidx = idx + where[i] - 1
|
||||
val = i-offs
|
||||
for j = idx:lastidx
|
||||
x[j] = val
|
||||
end
|
||||
idx = lastidx + 1
|
||||
end
|
||||
|
||||
return x
|
||||
end
|
||||
|
||||
"""
|
||||
sort(v; alg::Algorithm=defalg(v), lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)
|
||||
|
||||
Variant of [`sort!`](@ref) that returns a sorted copy of `v` leaving `v` itself unmodified.
|
||||
|
||||
# Examples
|
||||
|
||||
```jldoctest
|
||||
julia> v = [3, 1, 2];
|
||||
|
||||
julia> sort(v)
|
||||
3-element Array{Int64,1}:
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
julia> v
|
||||
3-element Array{Int64,1}:
|
||||
3
|
||||
1
|
||||
2
|
||||
```
|
||||
"""
|
||||
sort(v::AbstractVector; kws...) = sort!(copymutable(v); kws...)
|
||||
|
||||
## selectperm: the permutation to sort the first k elements of an array ##
|
||||
|
||||
selectperm(v::AbstractVector, k::Union{Integer,OrdinalRange}; kwargs...) =
|
||||
selectperm!(similar(Vector{eltype(k)}, indices(v,1)), v, k; kwargs..., initialized=false)
|
||||
|
||||
function selectperm!(ix::AbstractVector{<:Integer}, v::AbstractVector,
|
||||
k::Union{Int, OrdinalRange};
|
||||
lt::Function=isless,
|
||||
by::Function=identity,
|
||||
rev::Bool=false,
|
||||
order::Ordering=Forward,
|
||||
initialized::Bool=false)
|
||||
if !initialized
|
||||
@inbounds for i = indices(ix,1)
|
||||
ix[i] = i
|
||||
end
|
||||
end
|
||||
|
||||
# do partial quicksort
|
||||
sort!(ix, PartialQuickSort(k), Perm(ord(lt, by, rev, order), v))
|
||||
return ix[k]
|
||||
end
|
||||
|
||||
## sortperm: the permutation to sort an array ##
|
||||
|
||||
"""
|
||||
sortperm(v; alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)
|
||||
|
||||
Return a permutation vector of indices of `v` that puts it in sorted order. Specify `alg` to
|
||||
choose a particular sorting algorithm (see Sorting Algorithms). `MergeSort` is used by
|
||||
default, and since it is stable, the resulting permutation will be the lexicographically
|
||||
first one that puts the input array into sorted order – i.e. indices of equal elements
|
||||
appear in ascending order. If you choose a non-stable sorting algorithm such as `QuickSort`,
|
||||
a different permutation that puts the array into order may be returned. The order is
|
||||
specified using the same keywords as `sort!`.
|
||||
|
||||
See also [`sortperm!`](@ref).
|
||||
|
||||
# Examples
|
||||
|
||||
```jldoctest
|
||||
julia> v = [3, 1, 2];
|
||||
|
||||
julia> p = sortperm(v)
|
||||
3-element Array{Int64,1}:
|
||||
2
|
||||
3
|
||||
1
|
||||
|
||||
julia> v[p]
|
||||
3-element Array{Int64,1}:
|
||||
1
|
||||
2
|
||||
3
|
||||
```
|
||||
"""
|
||||
function sortperm(v::AbstractVector;
|
||||
alg::Algorithm=DEFAULT_UNSTABLE,
|
||||
lt=isless,
|
||||
by=identity,
|
||||
rev::Bool=false,
|
||||
order::Ordering=Forward)
|
||||
ordr = ord(lt,by,rev,order)
|
||||
if ordr === Forward && isa(v,Vector) && eltype(v)<:Integer
|
||||
n = _length(v)
|
||||
if n > 1
|
||||
min, max = extrema(v)
|
||||
(diff, o1) = sub_with_overflow(max, min)
|
||||
(rangelen, o2) = add_with_overflow(diff, oneunit(diff))
|
||||
if !o1 && !o2 && rangelen < div(n,2)
|
||||
return sortperm_int_range(v, rangelen, min)
|
||||
end
|
||||
end
|
||||
end
|
||||
p = similar(Vector{Int}, indices(v, 1))
|
||||
for (i,ind) in zip(eachindex(p), indices(v, 1))
|
||||
p[i] = ind
|
||||
end
|
||||
sort!(p, alg, Perm(ordr,v))
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
sortperm!(ix, v; alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward, initialized::Bool=false)
|
||||
|
||||
Like [`sortperm`](@ref), but accepts a preallocated index vector `ix`. If `initialized` is `false`
|
||||
(the default), `ix` is initialized to contain the values `1:length(v)`.
|
||||
|
||||
# Examples
|
||||
|
||||
```jldoctest
|
||||
julia> v = [3, 1, 2]; p = zeros(Int, 3);
|
||||
|
||||
julia> sortperm!(p, v); p
|
||||
3-element Array{Int64,1}:
|
||||
2
|
||||
3
|
||||
1
|
||||
|
||||
julia> v[p]
|
||||
3-element Array{Int64,1}:
|
||||
1
|
||||
2
|
||||
3
|
||||
```
|
||||
"""
|
||||
function sortperm!(x::AbstractVector{<:Integer}, v::AbstractVector;
|
||||
alg::Algorithm=DEFAULT_UNSTABLE,
|
||||
lt=isless,
|
||||
by=identity,
|
||||
rev::Bool=false,
|
||||
order::Ordering=Forward,
|
||||
initialized::Bool=false)
|
||||
if indices(x,1) != indices(v,1)
|
||||
throw(ArgumentError("index vector must have the same indices as the source vector, $(indices(x,1)) != $(indices(v,1))"))
|
||||
end
|
||||
if !initialized
|
||||
@inbounds for i = indices(v,1)
|
||||
x[i] = i
|
||||
end
|
||||
end
|
||||
sort!(x, alg, Perm(ord(lt,by,rev,order),v))
|
||||
end
|
||||
|
||||
# sortperm for vectors of few unique integers
|
||||
function sortperm_int_range(x::Vector{<:Integer}, rangelen, minval)
|
||||
offs = 1 - minval
|
||||
n = length(x)
|
||||
|
||||
where = fill(0, rangelen+1)
|
||||
where[1] = 1
|
||||
@inbounds for i = 1:n
|
||||
where[x[i] + offs + 1] += 1
|
||||
end
|
||||
cumsum!(where, where)
|
||||
|
||||
P = Vector{Int}(n)
|
||||
@inbounds for i = 1:n
|
||||
label = x[i] + offs
|
||||
P[where[label]] = i
|
||||
where[label] += 1
|
||||
end
|
||||
|
||||
return P
|
||||
end
|
||||
|
||||
## sorting multi-dimensional arrays ##
|
||||
|
||||
"""
|
||||
sort(A, dim::Integer; alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward, initialized::Bool=false)
|
||||
|
||||
Sort a multidimensional array `A` along the given dimension.
|
||||
See [`sort!`](@ref) for a description of possible
|
||||
keyword arguments.
|
||||
|
||||
# Examples
|
||||
|
||||
```jldoctest
|
||||
julia> A = [4 3; 1 2]
|
||||
2×2 Array{Int64,2}:
|
||||
4 3
|
||||
1 2
|
||||
|
||||
julia> sort(A, 1)
|
||||
2×2 Array{Int64,2}:
|
||||
1 2
|
||||
4 3
|
||||
|
||||
julia> sort(A, 2)
|
||||
2×2 Array{Int64,2}:
|
||||
3 4
|
||||
1 2
|
||||
```
|
||||
"""
|
||||
function sort(A::AbstractArray, dim::Integer;
|
||||
alg::Algorithm=DEFAULT_UNSTABLE,
|
||||
lt=isless,
|
||||
by=identity,
|
||||
rev::Bool=false,
|
||||
order::Ordering=Forward,
|
||||
initialized::Bool=false)
|
||||
order = ord(lt,by,rev,order)
|
||||
n = length(indices(A, dim))
|
||||
if dim != 1
|
||||
pdims = (dim, setdiff(1:ndims(A), dim)...) # put the selected dimension first
|
||||
Ap = permutedims(A, pdims)
|
||||
Av = vec(Ap)
|
||||
sort_chunks!(Av, n, alg, order)
|
||||
permutedims(Ap, invperm(pdims))
|
||||
else
|
||||
Av = A[:]
|
||||
sort_chunks!(Av, n, alg, order)
|
||||
reshape(Av, indices(A))
|
||||
end
|
||||
end
|
||||
|
||||
@noinline function sort_chunks!(Av, n, alg, order)
|
||||
inds = linearindices(Av)
|
||||
for s = first(inds):n:last(inds)
|
||||
sort!(Av, s, s+n-1, alg, order)
|
||||
end
|
||||
Av
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
sortrows(A; alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)
|
||||
|
||||
Sort the rows of matrix `A` lexicographically.
|
||||
See [`sort!`](@ref) for a description of possible
|
||||
keyword arguments.
|
||||
|
||||
# Examples
|
||||
|
||||
```jldoctest
|
||||
julia> sortrows([7 3 5; -1 6 4; 9 -2 8])
|
||||
3×3 Array{Int64,2}:
|
||||
-1 6 4
|
||||
7 3 5
|
||||
9 -2 8
|
||||
|
||||
julia> sortrows([7 3 5; -1 6 4; 9 -2 8], lt=(x,y)->isless(x[2],y[2]))
|
||||
3×3 Array{Int64,2}:
|
||||
9 -2 8
|
||||
7 3 5
|
||||
-1 6 4
|
||||
|
||||
julia> sortrows([7 3 5; -1 6 4; 9 -2 8], rev=true)
|
||||
3×3 Array{Int64,2}:
|
||||
9 -2 8
|
||||
7 3 5
|
||||
-1 6 4
|
||||
```
|
||||
"""
|
||||
function sortrows(A::AbstractMatrix; kws...)
|
||||
inds = indices(A,1)
|
||||
T = slicetypeof(A, inds, :)
|
||||
rows = similar(Vector{T}, indices(A, 1))
|
||||
for i in inds
|
||||
rows[i] = view(A, i, :)
|
||||
end
|
||||
p = sortperm(rows; kws..., order=Lexicographic)
|
||||
A[p,:]
|
||||
end
|
||||
|
||||
"""
|
||||
sortcols(A; alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)
|
||||
|
||||
Sort the columns of matrix `A` lexicographically.
|
||||
See [`sort!`](@ref) for a description of possible
|
||||
keyword arguments.
|
||||
|
||||
# Examples
|
||||
|
||||
```jldoctest
|
||||
julia> sortcols([7 3 5; 6 -1 -4; 9 -2 8])
|
||||
3×3 Array{Int64,2}:
|
||||
3 5 7
|
||||
-1 -4 6
|
||||
-2 8 9
|
||||
|
||||
julia> sortcols([7 3 5; 6 -1 -4; 9 -2 8], alg=InsertionSort, lt=(x,y)->isless(x[2],y[2]))
|
||||
3×3 Array{Int64,2}:
|
||||
5 3 7
|
||||
-4 -1 6
|
||||
8 -2 9
|
||||
|
||||
julia> sortcols([7 3 5; 6 -1 -4; 9 -2 8], rev=true)
|
||||
3×3 Array{Int64,2}:
|
||||
7 5 3
|
||||
6 -4 -1
|
||||
9 8 -2
|
||||
```
|
||||
"""
|
||||
function sortcols(A::AbstractMatrix; kws...)
|
||||
inds = indices(A,2)
|
||||
T = slicetypeof(A, :, inds)
|
||||
cols = similar(Vector{T}, indices(A, 2))
|
||||
for i in inds
|
||||
cols[i] = view(A, :, i)
|
||||
end
|
||||
p = sortperm(cols; kws..., order=Lexicographic)
|
||||
A[:,p]
|
||||
end
|
||||
|
||||
function slicetypeof(A::AbstractArray{T}, i1, i2) where T
|
||||
I = map(slice_dummy, to_indices(A, (i1, i2)))
|
||||
fast = isa(IndexStyle(viewindexing(I), IndexStyle(A)), IndexLinear)
|
||||
SubArray{T,1,typeof(A),typeof(I),fast}
|
||||
end
|
||||
slice_dummy(S::Slice) = S
|
||||
slice_dummy(::AbstractUnitRange{T}) where {T} = oneunit(T)
|
||||
|
||||
## fast clever sorting for floats ##
|
||||
|
||||
module Float
|
||||
using ..Sort
|
||||
using ...Order
|
||||
|
||||
import Core.Intrinsics: slt_int
|
||||
import ..Sort: sort!
|
||||
import ...Order: lt, DirectOrdering
|
||||
|
||||
const Floats = Union{Float32,Float64}
|
||||
|
||||
struct Left <: Ordering end
|
||||
struct Right <: Ordering end
|
||||
|
||||
left(::DirectOrdering) = Left()
|
||||
right(::DirectOrdering) = Right()
|
||||
|
||||
left(o::Perm) = Perm(left(o.order), o.data)
|
||||
right(o::Perm) = Perm(right(o.order), o.data)
|
||||
|
||||
lt(::Left, x::T, y::T) where {T<:Floats} = slt_int(y, x)
|
||||
lt(::Right, x::T, y::T) where {T<:Floats} = slt_int(x, y)
|
||||
|
||||
isnan(o::DirectOrdering, x::Floats) = (x!=x)
|
||||
isnan(o::Perm, i::Int) = isnan(o.order,o.data[i])
|
||||
|
||||
function nans2left!(v::AbstractVector, o::Ordering, lo::Int=first(indices(v,1)), hi::Int=last(indices(v,1)))
|
||||
i = lo
|
||||
@inbounds while i <= hi && isnan(o,v[i])
|
||||
i += 1
|
||||
end
|
||||
j = i + 1
|
||||
@inbounds while j <= hi
|
||||
if isnan(o,v[j])
|
||||
v[i], v[j] = v[j], v[i]
|
||||
i += 1
|
||||
end
|
||||
j += 1
|
||||
end
|
||||
return i, hi
|
||||
end
|
||||
function nans2right!(v::AbstractVector, o::Ordering, lo::Int=first(indices(v,1)), hi::Int=last(indices(v,1)))
|
||||
i = hi
|
||||
@inbounds while lo <= i && isnan(o,v[i])
|
||||
i -= 1
|
||||
end
|
||||
j = i - 1
|
||||
@inbounds while lo <= j
|
||||
if isnan(o,v[j])
|
||||
v[i], v[j] = v[j], v[i]
|
||||
i -= 1
|
||||
end
|
||||
j -= 1
|
||||
end
|
||||
return lo, i
|
||||
end
|
||||
|
||||
nans2end!(v::AbstractVector, o::ForwardOrdering) = nans2right!(v,o)
|
||||
nans2end!(v::AbstractVector, o::ReverseOrdering) = nans2left!(v,o)
|
||||
nans2end!(v::AbstractVector{Int}, o::Perm{<:ForwardOrdering}) = nans2right!(v,o)
|
||||
nans2end!(v::AbstractVector{Int}, o::Perm{<:ReverseOrdering}) = nans2left!(v,o)
|
||||
|
||||
issignleft(o::ForwardOrdering, x::Floats) = lt(o, x, zero(x))
|
||||
issignleft(o::ReverseOrdering, x::Floats) = lt(o, x, -zero(x))
|
||||
issignleft(o::Perm, i::Int) = issignleft(o.order, o.data[i])
|
||||
|
||||
function fpsort!(v::AbstractVector, a::Algorithm, o::Ordering)
|
||||
i, j = lo, hi = nans2end!(v,o)
|
||||
@inbounds while true
|
||||
while i <= j && issignleft(o,v[i]); i += 1; end
|
||||
while i <= j && !issignleft(o,v[j]); j -= 1; end
|
||||
i <= j || break
|
||||
v[i], v[j] = v[j], v[i]
|
||||
i += 1; j -= 1
|
||||
end
|
||||
sort!(v, lo, j, a, left(o))
|
||||
sort!(v, i, hi, a, right(o))
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
fpsort!(v::AbstractVector, a::Sort.PartialQuickSort, o::Ordering) =
|
||||
sort!(v, first(indices(v,1)), last(indices(v,1)), a, o)
|
||||
|
||||
sort!(v::AbstractVector{<:Floats}, a::Algorithm, o::DirectOrdering) = fpsort!(v,a,o)
|
||||
sort!(v::Vector{Int}, a::Algorithm, o::Perm{<:DirectOrdering,<:Vector{<:Floats}}) = fpsort!(v,a,o)
|
||||
|
||||
end # module Sort.Float
|
||||
|
||||
end # module Sort
|
||||
Reference in New Issue
Block a user