There is also Base.swapcols!, but again this is an internal function that may disappear in the future. But since it is only a 10-line function that doesn’t depend on any other Base internals it is perfectly reasonable to copy-and-paste it into your code as needed:
# swap columns i and j of a, in-place
function swapcols!(a::AbstractMatrix, i, j)
i == j && return
cols = axes(a,2)
@boundscheck i in cols || throw(BoundsError(a, (:,i)))
@boundscheck j in cols || throw(BoundsError(a, (:,j)))
for k in axes(a,1)
@inbounds a[k,i],a[k,j] = a[k,j],a[k,i]
end
end
It’s very similar to the suggestions above, except it adds an @inbounds annotation and consequently requires bounds checks before the loop. You could also do e.g.
if isdefined(Base, :swapcols!)
using Base: swapcols! # assumes the API hasn't changed
else
function swapcols!(...)
...
end
end
Inspecting Base code can be a useful exercise, even if you end up copy-pasting it for safety, since it usually has been reviewed by multiple people and tries extra hard to be robust and reasonably efficient.