Enumerate loop: problem with indexing (method error)


#1

Good afternoon,
Using an enumerate loop, I get an error method when trying to fill in a vector with value calculated at each iteration of the loop. Would anyone know how to solve it? Many thanks for your help.

grid = collect(range(0.01, length=3, stop=1.0))   
  X= Vector  
for (i, D) in enumerate(grid)
    X[i] = i * D
 end
MethodError: no method matching setindex!(::Type{Array{T,1} where T}, ::Float64, ::Int32)

Stacktrace:
 [1] top-level scope at .\In[95]:4


#2

Your X is not a Vector but a UnionAll, since you assigned X to be the type Vector, not an instance of it as you could with X = Vector().
But that gives you an empty vector which you can’t access with X[i], instead you can push!(X, i*D) to put i*D in X.
Even better, you allocate a vector of the correct length with X = Vector{Float64}(undef,3) and then fill in the values just as you did with the loop. This generally gives the best performance since you don’t have to allocate a new vector within the loop, only preallocate it once beforehand.

Cheers


#3

Wonderful Peter. You solved it so fast. many many thanks. Also your explanation is useful to avoid this type of errors in the future. Have a nice day!


#4

Firstly, there is no need to collect your range. In fact you should almost never do that, unless you have a very specific need. (For some reason, everyone wants to collect ranges all the time. Please don’t :smile: )

Secondly, here, I think a comprehension would be a very nice solution, and you don’t have to specify the type. Then your code becomes:

grid = range(0.01, length=3, stop=1.0)  # don't collect here!
X = [i * D for (i, D) in enumerate(grid)]

You could also try:

X = eachindex(grid) .* grid