someone
someone

Reputation: 195

undefined method [] for nil:NilClass (NoMethodError) in ruby... Why?

Here's my code:

begin
     items = CSV.read('somefile.csv')
     linesAmount = CSV.readlines('somefile.csv').size
     counter = 1
     while linesAmount >= counter do
       fullrow = items[counter]
       firstitem = fullrow[0] #This is the line that my code doesn't like.
       puts firstitem
       counter = counter + 1

     end


end

For some ruby doesn't like that one line, where I have firstitem = fullrow[0]. It throws me the undefined method [] error. BUT, in the console, I can still see it printing the firstitem... So it still prints it, but yet throws an error? What's going on?

However, if I take the first three lines in the while loop OUTSIDE of the while loop, and comment out everything in the loop other than the counter line, then I don't get any error. So if that firstitem line appears outside the while loop, the code thinks it's all fine.

Edit: I know that the arrays start from 0, but I specifically wanted counter to not care about the very first line. I forgot to mention that, sorry.

Edit2: Thank you everyone, I solved it by adding -1 after linesAmount, and it works!

Upvotes: 3

Views: 344

Answers (2)

spickermann
spickermann

Reputation: 106802

CSV.read and CSV.readlines return arrays. If your array contains two values, then size returns 2. But the indexes you need to call are items[0] and items[1]. Therefore this line

items[counter]

throws an error.

Change the line to

items[counter - 1]

and it should work.

Furthermore you can improve your code by using Ruby idioms:

begin
 items = CSV.read('somefile.csv')
 items.each do |item|
   puts item[0]
 end
end

Upvotes: 1

Marc
Marc

Reputation: 448

Looks like you have an off by one error, you are reading past the end of the items array. If there are 10 lines in the CSV file, the lines will be an array with indexes from 0 to 9, not 1 to 10.

Change your while to look like this

counter = 0
while counter < linesAmount
  ...
end

However a better approach overall would be to just do the following

CSV.readlines('somefile.csv').each do |line|
  puts line
end

Upvotes: 1

Related Questions