Skip to content

Adding perm version of sortslices #45787

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

Closed
wants to merge 4 commits into from
Closed
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
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ export
sortperm,
sortperm!,
sortslices,
sortslicesperm,
dropdims,
step,
stride,
Expand Down
117 changes: 116 additions & 1 deletion base/multidimensional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1792,7 +1792,7 @@ If `dims` is `(2, 1)` instead, the same slices will be taken,
but the result order will be row-major instead.

# Higher dimensional examples
```
```jldoctest
julia> A = permutedims(reshape([4 3; 2 1; 'A' 'B'; 'C' 'D'], (2, 2, 2)), (1, 3, 2))
2×2×2 Array{Any, 3}:
[:, :, 1] =
Expand Down Expand Up @@ -1880,3 +1880,118 @@ end

getindex(b::Ref, ::CartesianIndex{0}) = getindex(b)
setindex!(b::Ref, x, ::CartesianIndex{0}) = setindex!(b, x)

## sortslicesperm

"""
sortslicesperm(A; dims, alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)

Return a permutation vector `I` that sorts slices of an array `A`. The
required keyword argument `dims` must be either an integer or a tuple
of integers. It specifies the dimension(s) over which the slices are sorted.

E.g., if `A` is a matrix, `dims=1` will sort rows, `dims=2` will sort columns.
Note that the default comparison function on one dimensional slices sorts
lexicographically.

For the remaining keyword arguments, see the documentation of [`sort!`](@ref).

#Examples
```jldoctest
julia> sortslicesperm([7 3 5; -1 6 4; 9 -2 8], dims=1) # Sort rows
3-element Vector{Int64}:
2
1
3

julia> sortslicesperm([7 3 5; -1 6 4; 9 -2 8], dims=1, lt=(x,y)->isless(x[2],y[2]))
3-element Vector{Int64}:
3
1
2

julia> sortslicesperm([7 3 5; -1 6 4; 9 -2 8], dims=1, rev=true)
3-element Vector{Int64}:
3
1
2

julia> sortslicesperm([7 3 5; 6 -1 -4; 9 -2 8], dims=2) # Sort columns
3-element Vector{Int64}:
2
3
1

julia> sortslicesperm([7 3 5; 6 -1 -4; 9 -2 8], dims=2, alg=InsertionSort, lt=(x,y)->isless(x[2],y[2]))
3-element Vector{Int64}:
3
2
1

julia> sortslicesperm([7 3 5; 6 -1 -4; 9 -2 8], dims=2, rev=true)
3-element Vector{Int64}:
1
3
2
```

#Higher dimensions

`sortslicesperm` extends naturally to higher dimensions. E.g., if `A` is a
a 2x2x2 array, `sortslicesperm(A, dims=3)` will return the vector that will sort
slices within the 3rd dimension, passing the 2x2 slices `A[:, :, 1]` and
`A[:, :, 2]` to the comparison function. Note that while there is no default
order on higher-dimensional slices, you may use the `by` or `lt` keyword
argument to specify such an order.

If `dims` is a tuple, the order of the dimensions in `dims` is
relevant and specifies the linear order of the slices. E.g., if `A` is three
dimensional and `dims` is `(1, 2)`, the orderings of the first two dimensions
are re-arranged such that the slices (of the remaining third dimension) are sorted.
If `dims` is `(2, 1)` instead, the same slices will be taken,
but the result order will be row-major instead.

# Higher dimensional examples
```jldoctest
julia> A = permutedims(reshape([4 3; 2 1; 'A' 'B'; 'C' 'D'], (2, 2, 2)), (1, 3, 2))
2×2×2 Array{Any, 3}:
[:, :, 1] =
4 3
2 1

[:, :, 2] =
'A' 'B'
'C' 'D'

julia> sortslicesperm(A, dims=(1,2))
4-element Vector{Int64}:
4
2
3
1

julia> sortslicesperm(A, dims=(2,1))
4-element Vector{Int64}:
4
3
2
1

julia> sortslicesperm(reshape([5; 4; 3; 2; 1], (1,1,5)), dims=3, by=x->x[1,1])
5-element Vector{Int64}:
5
4
3
2
1
```
"""
function sortslicesperm(A::AbstractArray; dims::Union{Integer, Tuple{Vararg{Integer}}}, kws...)
_sortslicesperm(A, Val{dims}(); kws...)
end

function _sortslicesperm(A::AbstractArray, d::Val{dims}; kws...) where dims
itspace = compute_itspace(A, d)
vecs = map(its->view(A, its...), itspace)
p = sortperm(vecs; kws...)
end