Recently I stumbled upon a case where I for example have an array of arrays (a
) and a second memory already allocated (b
) – this might also be deeper nested than in the following example.
a = [[1],[2],[3]]
b = similar.(a)
Now if I want to copy the values and not the arrays, copyto!
won’t work with
copyto!(b,a)
b[3][1] = 4
I would also change a
. What’s the best way to copy the values (not references) of the inner arrays (recursively) as deepcopy
would do? Note that b
is allocated already, so deepcopy would allocate new memory here, which I would like to avoid.
Eg
map(copyto!, b, a)
but there are a lot of equivalent solutions (broadcasting, a loop, etc).
Thanks.
But this would just be one level of recursion, i.e. not work for arrays of arrays of arrays? (Similarly would copyto!.(a,b)
, right?
I would like a method that – as deep copy – does this on arbitrary levels. And sure, my MWE Is too small for that.
Something like
function recursive_copyto!(a::AbstractArray{T}, b::AbstractArray{T}) where {T}
if T <: AbstractArray
foreach(recursive_copyto!, a, b)
else
copyto!(a, b)
end
a
end
?
1 Like
That looks nice, maybe I would do that with dispatch?
function recursive_copyto!(a::AbstractArray{T}, b::AbstractArray{T}) where {T<:AbstractArray}
foreach(recursive_copyto!, a, b)
return a
end
function recursive_copyto!(a::AbstractArray{T}, b::AbstractArray{T}) where {T}
copyto!(a, b)
end
Sure, if you prefer doing the job of the compiler.
1 Like
Question. Given that arrays of arrays are in reality arrays of references to other arrays, and that they can change in size, etc.
When you do
a = [[1],[2],[[3,4,5]]]
b = similar.(a)
Are you allocating only enough space to get three pointers to other arrays, or are you really allocating the space for the three pointers and space for one Int associated with those pointers and then three ints in the inner array? I figure if your inside array has a more complicated layout I may become more difficult to really allocate everything at once?
The example above yields:
julia> a = [[1],[2],[[3,4,5]]]
3-element Vector{Vector{T} where T}:
[1]
[2]
[[3, 4, 5]]
julia> b = similar.(a)
3-element Vector{Vector{T} where T}:
[4831755376]
[4660659088]
[#undef]
What I wonder if is you really save something preallocating this instead of just doing a deepcopy
For types I prefer to not write it wit an if
, since I find the code cleaner. Is your code faster?
Oh, the point is, that in the original code my b
is already initialised fully, since it comes from somewhere else, so there is no deep copy I would like to do, I really just want to copy the values. So there is no similar.(...)
in my code. Initialilzation happens far before and I am sure both a
and b
are initialised and of same size, it actually is a point on the nested array PowerManifold (and maybe even a point on a power manifold of a power manifold, so even 3 levels of arrays)
Sorry if my MWE caused confusion there.
Oh, thanks for explaining and sorry for adding noise.
No problem – actually we also solve this recursive similar
problem you stumbled upon, which is (similar as asked here) just recursively applying similar, we call it allocate
in our package, see https://juliamanifolds.github.io/Manifolds.jl/latest/interface.html#Allocation.
No, there should be no speed difference. What you find cleaner is of course a matter of taste, just do it the way you prefer.
1 Like
Thanks for the clarification. Sure that is just a matter of taste. That’s why I also marked your answer as the solution. Thanks for the help