I’m trying to write a function which returns a random index for each dimension of an array.
It’s easy to do this if the dimensions of the array are known, but I want to abstract my function to work on arrays of arbitrary dimension.
The 1D case is very simple:
function rand_index_1D(a::AbstractVector)
return rand(1:length(a))
end
Similarly, the 2D case:
function rand_index_2D(a::AbstractMatrix)
i = rand(1:length(a[1,:]))
j = rand(1:length(a[:,1]))
return (i,j)
end
The trouble I’m having is writing a single function which will work for an array of any dimension. I’ve been trying to rewrite the 2D case into a loop, but I’m not sure how to slice the array correctly. What I have so far:
function rand_index_nD(a::AbstractArray)
dims = size(a)
nout = length(dims)
v = Vector{Int64}(undef, nout)
for n = 1:nout
# assign v[n] somehow
end
return v
end
I suspect that Julia has a built-in function (eachslice, selectdim, etc) which would really help here, but I haven’t quite figured it out.
If you want to avoid allocations, you could use an NTuple:
function uniform_index(a::AbstractArray{T, N}) where {T, N}
return ntuple(Val(N)) do i
rand(axes(a, i)) # safer than 1:size(a, i)
end
end
using BenchmarkTools
A = rand(2, 3, 4)
@btime uniform_index($A)
# 16.016 ns (0 allocations: 0 bytes)
# (2, 3, 2)
A more elegant and equally performant (or perhaps a bit faster) approach is to use CartesianIndices: