"ERROR: LoadError: BoundsError: attempt to access 0-element Array{Candidate,1} at index [1]" when trying to fill the empty array of a composite type

Viewed 6649

I get an error when trying to populate an empty array with input from a user.

const max = 9 # a maximal number of candidates

# Let us define a composite type for the candidates in our elections
mutable struct Candidate
    name::String
    votes::Int8
 end
 
 
candidates = Candidate[]

i = 1

while i < max
 println("Name of the candidate: ?")
 candidates[i].name = readline();
 println("Votes on him: ?")
 candidates[i].votes = parse(Int8, readline(), base=10);
 println("Thank you, let us move to the next candidate.")
 global i = i +1    
 end

After ("Name of the candidate: ?") being displayed, I get the following error:

ERROR: LoadError: BoundsError: attempt to access 0-element Array{Candidate,1} at index [1]
Stacktrace:
 [1] getindex(::Array{Candidate,1}, ::Int64) at ./array.jl:731
 [2] top-level scope at /home/jerzy/ComputerScience/SoftwareDevelopment/MySoftware/MyJulia/plurality.jl:18 [inlined]
 [3] top-level scope at ./none:0
 [4] include at ./boot.jl:317 [inlined]
 [5] include_relative(::Module, ::String) at ./loading.jl:1044
 [6] include(::Module, ::String) at ./sysimg.jl:29
 [7] exec_options(::Base.JLOptions) at ./client.jl:266
 [8] _start() at ./client.jl:425
in expression starting at /home/jerzy/ComputerScience/SoftwareDevelopment/MySoftware/MyJulia/plurality.jl:16

Alternatively, using

candidates = Array{Candidate}(undef, 0)

instead of

candidates = Candidate[]

results in:

ERROR: LoadError: UndefRefError: access to undefined reference

Apologies for being such a newbie. I relied on what I read in this wikibook. Would you refer me to some more reading?

1 Answers

You are almost correct, issue is that the length of your array is 0 (you can verify it with length(candidates)), so Julia complains when you are trying to set non-zero indexed elements of an array with candidates[i]. If you do not know length of your array in advance, then you should use push! function.

const max_candidates = 9 # a maximal number of candidates

while i < max_candidates
 println("Name of the candidate: ?")
 name = readline();
 println("Votes on him: ?")
 votes = parse(Int, readline());
 push!(candidates, Candidate(name, votes))
 println("Thank you, let us move to the next candidate.")
 global i = i + 1
end

I've changed here max to max_candidates because max interferes with Base max function.

If you know number of candidates, you can use candidates = Vector{Candidate}(undef, max_candidates) form of initialization, take notice of max_candidates instead of 0, because you should allocate vector of necessary length.

candidates = Vector{Candidate}(undef, max_candidates)

for i in 1:max_candidates
 println("Name of the candidate: ?")
 name = readline();
 println("Votes on him: ?")
 votes = parse(Int, readline());
 candidates[i] = Candidate(name, votes)
 println("Thank you, let us move to the next candidate.")
end

Take notice, that I changed while to for it may be or may be not useful in your case, but at least that lets you remove global i = i + 1 line.

If the last version suits you, then you could probably remove mutable from struct definition, it is usually better for performance.

Related