Is there a way to use enumerate of a multi-dimensional array, something like:
function new_matrix(matrix)
new_matrix = copy(matrix)
for (i,j,element) in enumerate(matrix)
new_matrix[i,j] = i*j*matrix[i,j]
end
return new_matrix
end
axes doesn’t include the value, unlike enumerate. And actually, it’s not enumerate you want, even for one-dimensional vectors. You should use pairs, since enumerate always starts counting at 1 no matter what sort of array you have (even 0-indexed arrays).
You can get (i, j) from calling Tuple(ind), but you should rather use the cartesian index directly:
function new_matrix(matrix)
new_matrix = copy(matrix)
for (ind, element) in pairs(matrix)
(i, j) = Tuple(ind)
new_matrix[ind] = i * j * matrix[ind] # or ind[1]*ind[2] * matrix[ind]
end
return new_matrix
end
function new_matrix(matrix::AbstractMatrix)
new_matrix = similar(matrix)
for ij in CartesianIndices(matrix)
new_matrix[ij] = ij[1]*ij[2]*matrix[ij]
end
return new_matrix
end
You could do for (ij, val) in zip(CartesianIndices(matrix), matrix) to be closer to enumerate, but it’s probably not worth enumerate is mainly useful for non-indexable collections. Update: there is also pairs, as mentioned by @DNFabove.
BTW, there are some not-so-nice things here. Don’t give your output matrix the same name as the function: new_matrix, that’s probably a bad idea. And a tip: use similar(matrix) instead of copy(matrix), it can be a lot faster.
Here’s some code that actually uses the pairs feature better:
function new_matrix(matrix)
matrix_ = similar(matrix)
for (ind, element) in pairs(matrix)
matrix_[ind] = ind[1] * ind[2] * element
end
return matrix_
end
And this code works for all array dimensionalities from 0 to N
function new_arr(arr)
arr_ = similar(arr)
for (ind, element) in pairs(arr)
arr_[ind] = prod(Tuple(ind)) * element
end
return arr_
end
new_matrix(matrix) = [ij[1]*ij[2]*matrix[ij] for ij in CartesianIndices(matrix)]
which has the advantage of more flexibly computing the return type. (e.g. if you have a Matrix{Bool} it will return a Matrix{Int} thanks to promotion.)
Surprisingly pairs can’t be used with map, otherwise this might be another neat way:
julia> map(enumerate(rand(Bool, 2,10))) do (i,v)
i * v
end
2×10 Matrix{Int64}:
0 0 5 0 9 11 0 0 0 0
2 0 0 8 10 0 14 0 18 0
julia> map(pairs(rand(Bool, 2,10))) do (i,v)
prod(i.I) * v
end
ERROR: map is not defined on dictionaries
Looking at the code above and without taking credit from the authors of all the clever solutions, for the lazy the fast and intuitive TensorCast is a friend, it trivially enumerates and provides elementwise access:
# N-dimensional very fast solution by @DNF
function new_arr(arr)
arr_ = similar(arr)
for (ind, element) in pairs(arr)
arr_[ind] = prod(Tuple(ind)) * element
end
return arr_
end
a = rand(4,3,2)
b = new_arr(a)
# Lazy solution using TensorCast (not as fast but versatile and easy to remember):
using TensorCast
@cast c[i,j,k] := i*j*k*a[i,j,k]
c == b # true