Hi,
I try to initialize a vector in two parts, for example, a vector with fifty 0’s then fifty 1’s.
I can create it in a loop, but it is not very concise:
function foo1()
a = Array{Int64}(undef, 100)
for i in 1:50
a[i]=0
end
for i in 51:100
a[i]=1
end
return a
end
julia> @btime foo1()
189.182 ns (1 allocation: 896 bytes)
I also can use vcat, but then, unnecessary allocations happen.
function foo(N)
a = Vector{Int64}(undef, 2N)
a[1:N] .= 0
a[N+1:end] .= 1
return a
end
# or, a little bit slower
function bar(N)
a = zeros(Int, 2N)
a[N+1:end] .= 1
return a
end
Slicing syntax on the left hand side of an assignment does not create a copy, but calls the setindex! function, and mutates a view of the array the supplied indices.
This returns a view of the last 50 indices, not the entire vector.
This bit did not need the collect, unless you really need a Vector instead of a generator. However, it seems that even without the collect it allocates a lot, what is really surprising to me.
Yes I’m using 1.6. I have no problem with the allocations proposed in the previous examples, as they do not allocate more than needed. I still don’t understand where the allocations in this specific example comes from.
Edit :
Oh, I see, maybe there is a place for improvement here ?
Not so much, generators save anonymous functions for the inner expression (here a function giving 0) and one runs into the issue of return type inference of functions in Julia
julia> G = (0 for i in 1:50)
Base.Generator{UnitRange{Int64}, var"#13#14"}(var"#13#14"(), 1:50)
julia> G.f
#13 (generic function with 1 method)
julia> G.f(1)
0