Imagine the following situation:
I create an array with a fixed size and every element in this array is another array.
In a loop, I want to push tuples to one array of the outer array.
So I want to modify one array which is an element of the outer array.
The following code example is a heavily simplified snippet from my code. Therefor, the code snippet doesn’t do anything useful.
# fill an array full of emty arrays
outer_array = fill([], dim1, dim2, dim3, ...)
# modifiying arrays of outer array (I choosed three for-loops instead of eachindex() because it is more similar to my original code)
for z in 1:dim1, for y in 1:dim2, for x in 1:dim3
# current solution to modify array
sub_arr = copy(outer_array[z, y, x])
push!(sub_array, (*content in tuple*))
outer_array[z, y, x] = sub_array
end
This solution is terrible slow, so there must be some better solutions, maybe without copying the array??
(if you do sub_array = outer_array[z, y, x], without the copy, that should work to, the assignment won’t copy the sub array).
In parallel, you should not use [], untyped, it is better if you, knowning the type of the tuples, use typeof(tuples)[], to have a concretely typed array.
Thank you (@Imiq , @DNF ) for your quick responses.
I think using fill was the main problem.
My current solution:
outer_array = [[] for _ in 1:dim1, _ in 1:dim2, _ in 1:dim3]
for z in 1:dim1, for y in 1:dim2, for x in 1:dim3
push!(outer_array[z, y, x], (*content in tuple*))
end
That works, but I don’t have type annotations yet. So how can I get rid of [] in the array comprehension and how can I assign the type Tuple to []?
I’m not sure if this has any significant impact here, but as Julia is column-major, the inner/fastest changing loop variable should correspond to z, and it seems to be x in your example. Try swapping the variables in the for loops.
Thank you, too. I already heard about Julia’s column-major order, but I never really paid attention to it.
So do you mean something like should be faster?
for x in 1:dim3, for y in 1:dim2, for x in 1:dim1
push!(outer_array[z, y, x], (*content in tuple*))
end
Do I have to change something else to work column-oriented or is not only the order of the loops important?
What is the type of (*content in tuple*)? Prepend that to []. For example, if it’s Tuple{Float64, Int}, you write
outer_array = [Tuple{Float64, Int}[] for _ in 1:dim1, _ in 1:dim2, _ in 1:dim3]
Elements that are consecutive in the first dimension will be consecutive in memory. But in this case, the elements are references to other arrays, located elsewhere (and those element will be consecutive), so in this case it is unlikely to make difference. Can’t hurt, though.
for zyx in eachindex(IndexCartesian(),outer_array)
z,y,x = Tuple(zyx) # only need this if you want to extract the individual indices
push!(outer_array[zyx], (*content in tuple*)) # could also index with [z,y,x]
end
This will work even if you change the number of dimensions in your array (except the z,y,x = Tuple(i) part won’t) or if you use an array with unusual indexing. This will also use an index order that is good for most standard Julia arrays.
EDIT: thanks to the commenter below for pointing out that I had originally written CartesianIndex() in my suggestion rather than the correct IndexCartesian().