From: Robert Klemme Date: 2013-06-22T02:09:43+09:00 Subject: Re: A question about assignment of multidimensional array error message --047d7b6da782ea437204dfad2011 Content-Type: text/plain; charset=ISO-8859-1 On Fri, Jun 21, 2013 at 6:16 PM, Ruby Student wrote: > Team, > > The piece of code below is giving me an error which I can't find the > solution. The assignment below for * > msgCount[r][c] = mtc *is trwoing an exception. which I list below. > > Any suggestions? > Yes, a lot. First of all your Ruby is not very idiomatic. The smallest issue is your naming with camelCase which in Ruby land is only used for class and module names. All others use snake_case. > ################################################################### > #Date READ ENTRY DELETE ALARM HOTLIST SITE # > #20130611 2000000 200000 200000 2000 2000 20000 # > #20130611 2000000 200000 200000 2000 2000 20000 # > ################################################################### > Is this above the file format? With or without all the hashes? > msgCount = Array.new # Empty array. Will have size of [r][7]. > Rows will grow > > fn = "/home/rb/MyData/dp/PR_LOGS/pr_time.log.*" > > msgTypes = ["read", "entry", "delete", "alarm", "hotlist", "site"] > > fnls = `ls #{fn}`.split # Create fnls = file names list > Don't use backticks for this. Just use file_name_list = Dir["/home/rb/MyData/dp/PR_LOGS/pr_time.log.*"] > fc = fnls.size # Number of files to be processed > > fnls.each do |f| # Process each file > r = 0 # Rows are controlled by fnls, number of > files > Do you really want to reset r to 0 for every file? That will mean that you will later be overwriting values when you do msgCount[r][c] = mtc. I don't think that is what you want. > lp,lg,dt = f.split('.') # this info will be used later > > 7.times do |c| # Process each column > mtc = `grep #{msgTypes[c]} #{f} | wc -l` # Get Message Type Count > I am not sure what the line above is supposed to do. What it currently _does_ is this: it searches in the current file for all lines containing the current "message type" and then counts the number of those lines. Btw, you can do the counting with "grep -c". This approach is quite inefficient because it will read each file 7 times. Oh wait, and there are only 6 elements in msgType! One more reason not to use a number to iterate the array but just use #each as everybody else. > *msgCount[r][c] = mtc* > r += 1 # Next row please > You are incrementing r 7 * # of file names. Is this really what you want? Don't you rather want to store counts per file? end > end > A more idiomatic way of doing what you are probably trying to do is this: store counts in nested Hashes based on file name and message type. msg_types = ["read", "entry", "delete", "alarm", "hotlist", "site"] line_counts = {} Dir["/home/rb/MyData/dp/PR_LOGS/pr_time.log.*"].each do |file_name| # better: ARGV.each do |file_name| counts = Hash.new 0 File.foreach file_name do |line| msg_types.each do |mt| counts[mt] += 1 if line.include? mt end end line_counts[file_name] = counts end # output for testing purposes only require 'pp' pp line_counts > *in `block (2 levels) in
': undefined method `[]=' for nil:NilClass > (NoMethodError)* > Joel has explained that already. Cheers robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/ --047d7b6da782ea437204dfad2011 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable



On Fri, Jun 21, 2013 at 6:16 PM, Ruby Student <= ;ruby.student@g= mail.com> wrote:
Team,

The piece of= code below is giving me an error which I can't find the solution. The = assignment below for
msgCount[r][c] =3D mtc
is trwoing an exception. which I list below.

Any suggestions?

= Yes, a lot. =A0First of all your Ruby is not very idiomatic. =A0The smalles= t issue is your naming with camelCase which in Ruby land is only used for c= lass and module names. =A0All others use snake_case.
=A0
#= ##################################################################
#Date=A0=A0=A0=A0=A0 READ=A0=A0=A0=A0 ENTRY=A0=A0=A0 DELETE=A0=A0=A0 ALARM= =A0=A0 HOTLIST=A0=A0 SITE=A0=A0=A0=A0 #
#20130611=A0 2000000=A0 200000= =A0=A0 200000=A0=A0=A0 2000=A0=A0=A0 2000=A0=A0=A0=A0=A0 20000=A0=A0=A0 # #20130611=A0 2000000=A0 200000=A0=A0 200000=A0=A0=A0 2000=A0=A0=A0 2000=A0= =A0=A0=A0=A0 20000=A0=A0=A0 #
##########################################= #########################

Is this above the file format? =A0With or without al= l the hashes?
=A0
m= sgCount =3D Array.new=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 # Empty array. Will = have size of [r][7]. Rows will grow

fn=A0=A0 =3D "/home/rb/MyData/dp/PR_LOGS/pr_time.log.*"
msgTypes =3D ["read", "entry", "delete", &q= uot;alarm", "hotlist", "site"]

fnls =3D `ls= #{fn}`.split=A0=A0=A0=A0=A0=A0=A0=A0 # Create fnls =3D file names list

Don= 9;t use backticks for this. =A0Just use

file_name_list =3D Dir["/home/rb/MyData/dp/PR_LOGS/pr_time.log.*&quo= t;]
=A0
fc =3D fnls.size=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 # Numbe= r of files to be processed

fnls.each do |f|=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 # Process each file
=A0=A0 r =3D 0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 # Rows are controlle= d by fnls, number of files

Do you really want= to reset r to 0 for every file? =A0That will mean that you will later be o= verwriting values when you do msgCount[r][c] =3D mtc. =A0I don't think = that is what you want.
=A0
= =A0=A0 lp,lg,dt =3D f.split('.')=A0=A0=A0=A0=A0 # this info will be= used later

=A0=A0 7.times do |c|=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 # Proce= ss each column
=A0=A0=A0=A0=A0 mtc =3D `grep #{msgTypes[c]} #{f} | wc -l= `=A0 # Get Message Type Count

I am not sure what the line above is supposed to do. = =A0What it currently _does_ is this: it searches in the current file for al= l lines containing the current "message type" and then counts the= number of those lines. =A0Btw, you can do the counting with "grep -c&= quot;.

This approach is quite inefficient because it wil= l read each file 7 times. =A0Oh wait, and there are only 6 elements in msgT= ype! =A0One more reason not to use a number to iterate the array but just u= se #each as everybody else.
=A0
=A0=A0= =A0=A0=A0 msgCount[r][c] =3D mtc
=A0=A0=A0=A0=A0 r +=3D 1=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 # Next row please

You are incrementing r 7 * # of =A0file names. =A0Is = this really what you want? =A0Don't you rather want to store counts per= file?

=A0=A0 end
end

A more idiomatic way of doing what you are probably trying t= o do is this: store counts in nested Hashes based on file name and message = type.

msg_types =3D ["read", "= ;entry", "delete", "alarm", "hotlist", &= quot;site"]

line_counts =3D {}

Dir["/home/rb/MyData/dp/PR_LOGS/pr_time.log.*"].each d= o |file_name|
# better: ARGV.each do |file_name|
=A0 co= unts =3D Hash.new 0

=A0 File.foreach file_name do = |line|
=A0 =A0 msg_types.each do |mt|
=A0 =A0 =A0 counts[mt] +=3D 1= if line.include? mt
=A0 =A0 end
=A0 end

=
=A0 line_counts[file_name] =3D counts
end
# output for testing purposes only
require 'pp'
pp line_counts

=A0
in `block (2 levels) in <main>': undefined me= thod `[]=3D' for nil:NilClass (NoMethodError)

Joel has explained that already.

Cheers
robert


--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
--047d7b6da782ea437204dfad2011--