undefined method `[]' for nil:NilClass - how to prevent?

M

Mmcolli00 Mom

This returns correct value so long as I do not use array[0]. The
error is:
searchArray.rb:13: undefined method `[]' for nil:NilClass (NoMethodError)
from shifting1.rb:7:in `each_line'
from shifting1.rb:7
Exit code: 1
#**************************************
#Searches through a text file and, at one row at a time, counts how many
occurrences of the value exist for the column. For instance, if word,
'bird' exists in column1 row1 then count how many birds exist for the
whole column. Next..count the occurrences of bird in the column 2. If
the numbers do not match then outputs "Value does not contain a match:"
+Value.

I am having this issue with NilClass a lot this week. What do you think
I should change?

##start code

col1 = 0
col2 = 0

File.open('temp.txt', 'r+').each_line do |temp|
array = []
i = 0
array = temp.chomp.split(",",0)

arrayVal1 = array[0]
arrayVal2 = array[1]

if array[0] == arrayVal1 then
col1 = col1 + 1
end

if array[1] == arrayVal2 then
col2 = col2 + 1
end
i = i + 1

if col1 != col2 then
puts "Value does not contain a match:"
puts arrayVal1
end

end

##end code

Attachments:
http://www.ruby-forum.com/attachment/3164/searchArray.rb
 
R

Robert Klemme

This returns correct value so long as I do not use array[0]. The
error is:
searchArray.rb:13: undefined method `[]' for nil:NilClass (NoMethodError)
from shifting1.rb:7:in `each_line'
from shifting1.rb:7
Exit code: 1
#**************************************
#Searches through a text file and, at one row at a time, counts how many
occurrences of the value exist for the column. For instance, if word,
'bird' exists in column1 row1 then count how many birds exist for the
whole column. Next..count the occurrences of bird in the column 2. If
the numbers do not match then outputs "Value does not contain a match:"
+Value.

I am having this issue with NilClass a lot this week. What do you think
I should change?


The whole piece of code. No seriously, there are quite a few things to say:

##start code

col1 = 0
col2 = 0

File.open('temp.txt', 'r+').each_line do |temp|

The file handle is not closed properly. Rather use the block form of
File.open. Also, since you do not write the file, you can as well use

File.foreach 'temp.txt' do |temp|
....
end

Btw, the name "temp" doesn't tell much about the contents of the
variable. I'd pick another, more meaningful name like "line".
array = []

Superfluous initialization...
i = 0
array = temp.chomp.split(",",0)

.... because here you overwrite "array" immediately without reading it.
arrayVal1 = array[0]
arrayVal2 = array[1]

if array[0] == arrayVal1 then


As far as I can see this does not make sense: the comparison can never
be "true" because you compare an object (array[0]) with part of it
(array[0]).
col1 = col1 + 1
end

if array[1] == arrayVal2 then
col2 = col2 + 1
end
i = i + 1

if col1 != col2 then
puts "Value does not contain a match:"
puts arrayVal1
end

I have no idea what this is supposed to do: you compare global counts of
matches for every line. But: if there once was a mismatch in a line,
counts will not be the same in the next matching line. Is this really
what you want? Your description does not make this clear.

The whole bit certainly does not match your description. How about:

counts = values = nil

File.foreach 'temp.txt' do |line|
line.chomp!
# better use CSV parsing:
fields = line.split ','

if values
fields.each_with_index |f,i|
counts += 1 if values == f
end
else
# init search strings
values = fields
counts = Array.new(values.size, 0)
end
end

Cheers

robert
 
B

Brian Candler

Mmcolli00 said:
#Searches through a text file and, at one row at a time, counts how many
occurrences of the value exist for the column. For instance, if word,
'bird' exists in column1 row1 then count how many birds exist for the
whole column. Next..count the occurrences of bird in the column 2. If
the numbers do not match then outputs "Value does not contain a match:"
+Value.

--- Here's a simple version

count1 = Hash.new(0) # word => count in col1
count2 = Hash.new(0) # word => count in col2

File.open("temp.txt") do |src|
src.each_line do |line|
word1, word2 = line.chomp.split(",")
count1[word1] += 1
count2[word2] += 1
end
end

words = (count1.keys + count2.keys).uniq
words.each do |word|
if count1[word] != count2[word]
puts "Value does not contain a match: #{word}"
end
end

--- However you can remove some duplication by choice
--- of a suitable data structure: a single hash which maps
--- to an array giving the counts in col1 and col2

# word => [col1_count, col2_count]
counts = Hash.new { |h,k| h[k] = Array.new(2,0) }

File.open("temp.txt") do |src|
src.each_line do |line|
line.chomp.split(",").each_with_index do |word, i|
counts[word] += 1
end
end
end
counts.each do |word, cols|
if cols.uniq.size != 1
puts "Word #{word.inspect} occurs different times: #{cols.inspect}"
end
end
 
A

Axel Etzold

-------- Original-Nachricht --------
Datum: Thu, 15 Jan 2009 13:51:06 +0900
Von: Mmcolli00 Mom <[email protected]>
An: (e-mail address removed)
Betreff: undefined method `[]\' for nil:NilClass - how to prevent?
This returns correct value so long as I do not use array[0]. The
error is:
searchArray.rb:13: undefined method `[]' for nil:NilClass (NoMethodError)
from shifting1.rb:7:in `each_line'
from shifting1.rb:7
Exit code: 1
#**************************************
#Searches through a text file and, at one row at a time, counts how many
occurrences of the value exist for the column. For instance, if word,
'bird' exists in column1 row1 then count how many birds exist for the
whole column. Next..count the occurrences of bird in the column 2. If
the numbers do not match then outputs "Value does not contain a match:"
+Value.

I am having this issue with NilClass a lot this week. What do you think
I should change?

##start code

col1 = 0
col2 = 0

File.open('temp.txt', 'r+').each_line do |temp|
array = []
i = 0
array = temp.chomp.split(",",0)

arrayVal1 = array[0]
arrayVal2 = array[1]

if array[0] == arrayVal1 then
col1 = col1 + 1
end

if array[1] == arrayVal2 then
col2 = col2 + 1
end
i = i + 1

if col1 != col2 then
puts "Value does not contain a match:"
puts arrayVal1
end

end

##end code

Attachments:
http://www.ruby-forum.com/attachment/3164/searchArray.rb


Hi ---
in some lines of your data, the split function doesn't find the appropriate pattern, so you have
array==[], and thus, there isn't any array[0], i.e. array[0]==nil, and for nil, which is NilClass rather
than Array, there are no elements defined.
An alternative would be to do something like this:

begin
arrayVal1 = array[0]
rescue
arrayVal1=["something_else_you'll_have_to_fill_in"]
end
begin
arrayVal2 = array[0]
rescue
arrayVal2=["still_something_else_you'll_have_to_fill_in"]
end

which will try to execute the first statement after "begin", and if that fails, the statement after "rescue".
A conceptually cleaner way yet would be to assign a default value to the array variable,

array=Array.new(['nothing in here'])

Best regards,

Axel
 
M

Mmcolli00 Mom

Brian Thanks!! Your code does exactly what I am needing it to do. Thanks
for taking out the duplicates also. You are very skillful!

This error occurred:
I'll am looking to see if maybe I am missing a gem, not sure.
Value does not contain a match: Clashifting.rb:55: undefined method `+' for >nil:NilClass (NoMethodError)
from shifting.rb:143:in `each_with_index'
from shifting.rb:54:in `each'
from shifting.rb:54:in `each_with_index'
from shifting.rb:54
from shifting.rb:53:in `each_line'
from shifting.rb:53
from shifting.rb:52:in `open'
from shifting.rb:52

snippet of your code:

File.open("temp.txt") do |src|
src.each_line do |line|
line.chomp.split(",").each_with_index do |word, i|
counts[word] += 1 #line 55
end
end
end
counts.each do |word, cols|
if cols.uniq.size != 1
puts "Word #{word.inspect} occurs different times: #{cols.inspect}"
end
end
 
B

Brian Candler

Axel said:
A conceptually cleaner way yet would be to assign a default value to the
array variable,

array=Array.new(['nothing in here'])

Note: unlike Hashes, Arrays don't have default values.

When creating an Array, you can fill it with a specific number of
values:

array = Array.new(5,99) # [99,99,99,99,99]

This form inserts n identical references to the *same* object. If you
want distinct objects, then you have to use the block form:

array = Array.new(5) { ['nothing in here'] }

Regards,

Brian.
 
B

Brian Candler

Mmcolli00 said:
I'll am looking to see if maybe I am missing a gem, not sure.
Value does not contain a match: Clashifting.rb:55: undefined method `+' for >nil:NilClass (NoMethodError)
..

counts[word] += 1 #line 55


Well, this expression is a shortcut for

counts[word] = counts[word] + 1

so this means that counts[word] (on the right hand side) is nil. This
will occur if a line of your data file has more than 2 columns.

Note that

counts['someword'] is initialised to Array(2,0), which is [0,0]

so:

counts['someword'][0] is 0
counts['someword'][1] is 0
counts['someword'][2] is nil .. same for [3], [4] etc.

So it's reading past the end of the array, getting nil, and trying to
add 1 to it. The expression nil + 1 is meaningless, of course.

The solution depends on what you want to happen when your program reads
a line of the form "a,b,c"

* Do you want to treat "a" as the first word, and "b,c" as the second?
* Do you want to treat "a" and "b" as words, and ignore the rest of the
line?

Suitable adjustment to the 'split' expression should do the trick.

irb(main):001:0> "a,b,c".split(",",2)
=> ["a", "b,c"]
irb(main):002:0> "a,b,c".split(",")[0,2]
=> ["a", "b"]

HTH,

Brian.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,992
Messages
2,570,220
Members
46,805
Latest member
ClydeHeld1

Latest Threads

Top