Permuting the rows of a matrix based on given a given permutation

Suppose I am given an mXn matrix A, and I have a permutation of {1,…,m}, for example by

p = sortperm(A[:,1]);

I now wish to rearrange the wors of A based on p. How do I do that ? The permute!() function only applies to vectors, as shown here. I can always loop over the columns, as in

for j in 1:size(A,2)
     permute!(A[:,j], p);
end

but is there a better way ?

1 Like

Note that this permutes a copy of the column, unless you switch to using views (e.g. wrapping the code block or the line in a @views macro call).

For an alternative approach, you could write something similar to the Base.permutecols!! function (which permutes columns, not rows). (Since Julia’s Array is column-major, however, permuting rows with this algorithm will probably not be as efficient as permuting columns.) Or your could rearrange your code to swap dimensions on your array, and then call the Base.permutecols!! function directly. (It has a double !! because it also overwrites the permutation array p.)

3 Likes

Is this a (new) convention? Is it meant to signify that more than one passed argument is being mutated, or is its meaning more specific?

A couple of Base functions use it to indicate that multiple arguments are mutated, but I don’t think it’s a very widespread convention in Julia.

2 Likes

You can use sortslices, it sorts by rows, columns, or any row/column specified by the user.

julia> A = rand(0:9,5,5)
5×5 Array{Int64,2}:
 4  6  4  6  3
 2  7  5  5  2
 7  7  0  4  3
 4  5  2  5  6
 6  5  8  1  0

julia> sortslices(A, dims=1)
5×5 Array{Int64,2}:
 2  7  5  5  2
 4  5  2  5  6
 4  6  4  6  3
 6  5  8  1  0
 7  7  0  4  3
1 Like

Thank you. Although I was looking for an in-place algorithm, this function is a very useful to learn. From the examples that you provided, it seems that the sorting is only according to the first column or row. But what if I try to rearrange the rows in in increasing order of the second column ? You said that it can be done, could you give me the code to do it ? Julia’s documentation on sortclices does not provide a solution.

Thank you, however the function permutecolums itself did not work.

julia> permutecols!!(A,p)
ERROR: UndefVarError: permutecols!! not defined
Stacktrace:
 [1] top-level scope at none:0

In fact, it seems that Base does not have any such function defined.

julia> Base.permute
permute!     permute!!     permutedims   permutedims!

In the hyperlink that you provided, the function was defined in the Combinatorics.jl package. importing the package also did not work. I tried copying the function definition and explicitly defining permutecolumns!!. But this gives the error

julia> permutecols!!(A,p)
ERROR: UndefVarError: require_one_based_indexing not defined
Stacktrace:
 [1] permutecols!!(::Array{Float64,2}, ::Array{Int64,1}) at .\REPL[22]:2
 [2] top-level scope at none:0

Yes, as I said you can sort by any row/column you want which can be very useful. Just override the lt function to specify how the new comparison is done. Searching for documentation inside the REPL is so easy, just type ?sortslices and you get good examples.

julia> A = rand(0:9,5,5)
5×5 Array{Int64,2}:
 6  5  5  0  0
 3  4  5  9  5
 0  2  5  0  5
 9  9  1  7  2
 3  1  2  4  7

julia> sortslices(A, dims=1, lt=(x,y)->isless(x[2],y[2]))
5×5 Array{Int64,2}:
 3  1  2  4  7
 0  2  5  0  5
 3  4  5  9  5
 6  5  5  0  0
 9  9  1  7  2
1 Like

Thanks. I did search for sortslices. But there is no way anyone can possibly understand from the documentation alone that lt=(x,y)->isless(x[2],y[2])) is supposed to mean ``by second column".

It was added in Julia 1.2.

1 Like

You can also write sortslices(A, dims=1, by=row->row[2]), although I agree it’s not super-obvious what’s going to happen.

3 Likes

I see

I think this code doesn’t work b/c you haven’t specified j