This returns correct value so long as I do not use array[0][i]. 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][i] arrayVal2 = array[1][i] 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
on 2009-01-15 05:52
on 2009-01-15 08:06
On 15.01.2009 05:51, Mmcolli00 Mom wrote: > 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][i] > arrayVal2 = array[1][i] > > 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][i]). > 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. > end > > ##end code > > Attachments: > http://www.ruby-forum.com/attachment/3164/searchArray.rb 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[i] += 1 if values[i] == f end else # init search strings values = fields counts = Array.new(values.size, 0) end end Cheers robert
on 2009-01-15 10:31
Mmcolli00 Mom wrote: > #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][i] += 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
on 2009-01-15 10:38
-------- Original-Nachricht -------- > Datum: Thu, 15 Jan 2009 13:51:06 +0900 > Von: Mmcolli00 Mom <mmc_collins@yahoo.com> > An: ruby-talk@ruby-lang.org > Betreff: undefined method `[]\' for nil:NilClass - how to prevent? > occurrences of the value exist for the column. For instance, if word, > col1 = 0 > if array[0] == arrayVal1 then > puts arrayVal1 > Posted via http://www.ruby-forum.com/. 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][i] rescue arrayVal1=["something_else_you'll_have_to_fill_in"] end begin arrayVal2 = array[0][i] 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
on 2009-01-15 20:58
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][i] += 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
on 2009-01-15 21:59
Axel Etzold wrote: > 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.
on 2009-01-15 22:08
Mmcolli00 Mom wrote: > 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][i] += 1 #line 55 Well, this expression is a shortcut for counts[word][i] = counts[word][i] + 1 so this means that counts[word][i] (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.
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.