Reputation: 941
What's the best way to build a Julia array element by element when I am not sure of the final array size? In my problem, I am building the array in a single for loop.
So far, I have figured out I can either push into the array or index into a pre-allocated array:
using BenchmarkTools
function push_to_array!(array, N)
for i in 1:N
# some computation
push!(array, rand(Int64))
end
end
function fill_array!(array, N)
for i in 1:N
# some computation
array[i]=rand(Int64)
end
end
N = 100_000_000 # unknown in the real problem
empty = Vector{Int64}()
preallocated = Vector{Int64}(undef, 2*N) # 2*N represents some upper bound on N
@btime push_to_array!(empty, N)
# 28.272 s (6 allocations: 0 bytes)
@btime fill_array!(preallocated, N)
# 2.449 s (0 allocations: 0 bytes)
So filling a pre-allocated array is a lot faster than pushing, however, it's a bit cumbersome as I need to trim the output with correct_size = preallocated[1:N]
.
Is there a faster/better way of doing this?
Upvotes: 2
Views: 709
Reputation: 42214
In Julia you have views - no trimming required. Simply do:
correct_size = @view preallocated[1:1_000_000]
or
correct_size = view(preallocated, 1:1_000_000)
Now this operation is very cheap (BTW note also that you are not bencharking correctly as @time
measures both compile time and execution time):
julia> using BenchmarkTools
julia> @btime correct_size = @view $preallocated[1:1_000_000];
1.800 ns (0 allocations: 0 bytes)
In conclusion making a view
is basically free.
Finally, note that you can just resize!
the array (the time cost is the same as in case of a @view
):
resize!(preallocated, 1_000_000)
Upvotes: 5