Is it possible to automate this:
#I currently have:
y_TX, m_TX, ŷ_TX, ATT_TX, ATT_co, se_i_TX, se_t_TX = [], [], [], [], [], [], []
# I want something like:
y_TX, m_TX, ŷ_TX, ATT_TX, ATT_co, se_i_TX, se_t_TX = []
Is it possible to automate this:
#I currently have:
y_TX, m_TX, ŷ_TX, ATT_TX, ATT_co, se_i_TX, se_t_TX = [], [], [], [], [], [], []
# I want something like:
y_TX, m_TX, ŷ_TX, ATT_TX, ATT_co, se_i_TX, se_t_TX = []
You can do:
y_TX, m_TX, ŷ_TX, ATT_TX, ATT_co, se_i_TX, se_t_TX = ntuple(_ -> [], 7)
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.
Thanks but I keep adding new variables as I write, is it possible to do something like
a, b, c = ([] for _ in 1:end)
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...
Could use Iterators.repeated
here:
julia> using .Iterators: repeated
julia> a, b, c = repeated([]);
julia> a
Any[]
julia> b
Any[]
julia> c
Any[]
That just repeats the same object though, using the comprehension makes independent []
's.
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
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.
good catch!
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.
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+
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])
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))