# Automate allocation

Is it possible to automate this:

``````#I currently have:
y_TX, m_TX, ŷ_TX, ATT_TX, ATT_co, se_i_TX, se_t_TX = [], [], [], [], [], [], []
# I want something like:
y_TX, m_TX, ŷ_TX, ATT_TX, ATT_co, se_i_TX, se_t_TX = []
``````
1 Like

You can do:

``````y_TX, m_TX, ŷ_TX, ATT_TX, ATT_co, se_i_TX, se_t_TX = ntuple(_ -> [], 7)
``````
8 Likes

You can do something like

``````a, b, c = ([] for _ in 1:3)
``````

Be careful, because that way the arrays are of type Any, thus inefficient.

3 Likes

Thanks but I keep adding new variables as I write, is it possible to do something like

``````a, b, c = ([] for _ in 1:end)
``````
1 Like

You could just pick a really big upper bound, only the elements of the iterator you actually use will be created:

``````a, b, c       = ([] for _ in 1:1000)
a, b, c, d    = ([] for _ in 1:1000)
a, b, c, d, e = ([] for _ in 1:1000)
# etc...
``````
6 Likes

Could use `Iterators.repeated` here:

``````julia> using .Iterators: repeated

julia> a, b, c = repeated([]);

julia> a
Any[]

julia> b
Any[]

julia> c
Any[]
``````
2 Likes

That just repeats the same object though, using the comprehension makes independent `[]`'s.

7 Likes
``````julia> using .Iterators: repeated

julia> a, b, c = repeated([]);

julia> push!(a, 2)
1-element Array{Any,1}:
2

julia> b
1-element Array{Any,1}:
2

``````
3 Likes

If you do not mind a new struct type:

``````struct OnRepeat{F}
f :: F
end

function Base.iterate(o :: OnRepeat{F}, s :: Nothing = nothing) where {F}
return o.f(), nothing
end

a, b, c = OnRepeat(() -> [])
``````

And now you can use `OnRepeat` with any function taking no arguments and returning the new object you want.

7 Likes

good catch!

1 Like

I’ve sometimes defined a macro to help with this exact scenario,

``````macro repeated(x)
:((\$(esc(x))) for _ in Iterators.repeated(nothing))
end
``````

then you can do

``````a, b, c = @repeated([])
``````

I think I even proposed adding this to Base.Iterators but there were some valid concerns which I forget the details of now though.

5 Likes

could also just do

``````copy_repeated(x) = (copy(x) for x in Iterators.repeated(x))
``````

then

``````julia> a, b, c = copy_repeated([])
Base.Generator{Base.Iterators.Repeated{Vector{Any}}, typeof(copy)}(copy, Base.Iterators.Repeated{Vector{Any}}(Any[]))

julia> push!(a, 1)
1-element Vector{Any}:
1

julia> b
Any[]
``````

(or `Iterators.map(copy, repeated(x))` if you’re on 1.6+

6 Likes

There are some issues w/ some of the methods proposed above.

Method 1:

``````julia> zs = zeros(3)
3-element Vector{Float64}:
0.0
0.0
0.0

julia> a, b, c = (zs for _ in 1:100)
Base.Generator{UnitRange{Int64}, var"#33#34"}(var"#33#34"(), 1:100)

julia> a, b, c, zs
([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])

julia> b = ones(3)
3-element Vector{Float64}:
1.0
1.0
1.0

julia> a, b, c, zs # only b is changed
([0.0, 0.0, 0.0], [1.0, 1.0, 1.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])

julia> a[1:2] = ones(2)
2-element Vector{Float64}:
1.0
1.0

julia> a, b, c, zs # a, c, zs are changed, but not b. Why?
([1.0, 1.0, 0.0], [1.0, 1.0, 1.0], [1.0, 1.0, 0.0], [1.0, 1.0, 0.0])
``````

When I change `b` to a new vector, only b is changed, while `a, c, zs` are unchanged.
When I change some elements of `a` to a new vector, then `a, c, zs` are all changed in the same way, while `b` is unchanged.

Method 2:

``````julia> copy_repeated(x) = (copy(x) for x in Iterators.repeated(x))
copy_repeated (generic function with 1 method)

julia> zs = zeros(3)
3-element Vector{Float64}:
0.0
0.0
0.0

julia> a, b, c = copy_repeated(zs)
Base.Generator{Base.Iterators.Repeated{Vector{Float64}}, typeof(copy)}(copy, Base.Iterators.Repeated{Vector{Float64}}([0.0, 0.0, 0.0]))

julia> a, b, c, zs
([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])

julia> b = ones(3)
3-element Vector{Float64}:
1.0
1.0
1.0

julia> a, b, c, zs # only b is changed
([0.0, 0.0, 0.0], [1.0, 1.0, 1.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])

julia> a[1:2] = ones(2)
2-element Vector{Float64}:
1.0
1.0

julia> a, b, c, zs # only a is changed
([1.0, 1.0, 0.0], [1.0, 1.0, 1.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])
``````

@Mason’s method gives me what I expected.

Q: is the behavior of the 1st method `a, b, c = (zs for _ in 1:100)` as intended?

Here you assigned `b` to be a new vector of ones. If you wanted to mutate the vector that was there, you must use ` b .= 1`, or `b[1] = 1`, etc.:

``````julia> zs = zeros(3);

julia> a, b, c = (zs for _ in 1:3)
Base.Generator{UnitRange{Int64}, var"#1#2"}(var"#1#2"(), 1:3)

julia> a
3-element Vector{Float64}:
0.0
0.0
0.0

julia> a[1] = 1
1

julia> a,b,c
([1.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 0.0, 0.0])

``````

Ah, I see you already noted that. Yes, that is the expected behavior. If you don’t want the vectors to be the same, you need to copy them:

``````julia> a, b, c = (copy(zs) for _ in 1:3)
Base.Generator{UnitRange{Int64}, var"#3#4"}(var"#3#4"(), 1:3)

julia> a
3-element Vector{Float64}:
1.0
0.0
0.0

julia> a[1] = 2
2

julia> a, b, c
([2.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 0.0, 0.0])

``````
3 Likes

Yes.
We talked about assignment vs copy here.

I brought this up in case future users come to this thread, so the diff betw the following is clear:

``````a, b, c = (zs for _ in 1:3)
a, b, c = (copy(zs) for _ in 1:3)

a, b, c = (copy(zs) for i in Iterators.repeated(zs))
``````
3 Likes