Parse file to hash in Ruby - ruby
I'm a ruby newcomer who's trying to read a text file (a Valgrind simulation output) like this:
--------------------------------------------------------------------------------
Profile data file 'temp/gt_1024_2_16.out'
--------------------------------------------------------------------------------
I1 cache: 1024 B, 16 B, 2-way associative
D1 cache: 32768 B, 64 B, 8-way associative
LL cache: 3145728 B, 64 B, 12-way associative
Profiled target: bash run.sh
Events recorded: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Events shown: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Event sort order: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Thresholds: 99 0 0 0 0 0 0 0 0
Include dirs:
User annotated:
Auto-annotation: off
--------------------------------------------------------------------------------
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
--------------------------------------------------------------------------------
1,894,017 246,981 2,448 519,124 4,691 2,792 337,817 1,846 1,672 PROGRAM TOTALS
// other data
I want to extract the PROGRAM TOTALS table and put it into a hash. Something like...
myHash = { :Ir => 1894017, :I1mr => 246981, ILmr => 2448, ..., DLmw => 1672 }
What are the best options for doing this? Could the CSV classes help me out? Thanks a bunch.
My current code:
file = File.open(fileName, "r")
while header = file.gets
if header =~ / Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw /
# Found the header
file.gets # skip the ---- line
values = file.gets
puts "Header: " + header
puts " Data: " + values
break
end
end
I've got this output:
Header: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Data: 1,894,017 246,981 2,448 519,124 4,691 2,792 337,817 1,846 1,672 PROGRAM TOTALS
How could I join these two strings into a hash?
look at:
NAMES_INDEX = 16 # the line number of Ir I1mr ILmr Dr ...
NUMBERS_INDEX = 18 # the line number of 1,894,017 246,981 2,448 ...
FILE_NAME= "temp/gt_1024_2_16.out" # the file name
f = f = File.readlines(FILE_NAME)
names = f[NAMES_INDEX].split
numbers = f[NUMBERS_INDEX].split[0..-3].map{|a| a.delete(",").to_i}
h = Hash[names.zip numbers]
p h
It looks like your column names are fixed, since you search for them to find the data line.
This is how I would do it
data = nil
names = %w/ Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw /
open('E:\Perl\source\valgrind.txt', 'r') do |f|
f.each_line do |line|
if line =~ /PROGRAM TOTALS/
values = line.scan(/[\d\,]+/).map { |num| num.tr(',', '').to_i }
data = Hash[ names.zip(values) ]
break
end
end
end
p data
output
{"Ir"=>1894017, "I1mr"=>246981, "ILmr"=>2448, "Dr"=>519124, "D1mr"=>4691, "DLmr"=>2792, "Dw"=>337817, "D1mw"=>1846, "DLmw"=>1672}
I would write the code like this:
file_path, lines_with_data = 'data.txt', [16,18]
header, data = File.readlines(file_path)
.values_at(*lines_with_data)
.map{|line| line.strip.gsub(',','')
.split(/\s+/)}
data.map!(&:to_i)
p Hash[header.zip(data)] # => {"Ir"=>1894017, "I1mr"=>246981, "ILmr"=>2448, "Dr"=>519124, "D1mr"=>4691, "DLmr"=>2792, "Dw"=>337817, "D1mw"=>1846, "DLmw"=>1672}
Related
Remove nTh record from array using loop [closed]
Closed. This question needs debugging details. It is not currently accepting answers. Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question. Closed 6 years ago. Improve this question I'm writing a program that reads a .csv file, and then loops through it removing every 10th record it encounters before outputting it. I've been stuck on what I believe is a syntax issue for a while now and just can't seem to nail it. Anyone mind having a look? lines = [] i = 0 elements = [] element2 = [] output = [] file = File.open("./properties.csv", "r") while (line = file.gets) i += 1 # use split to break array up using commas arr = line.split(',') elements.push({ id: arr[0], streetAddress: arr[1], town: arr[2], valuationDate: arr[3], value: arr[4] }) end file.close # filter out blanks and nill rows x = elements.select { |elements| elements[:id].to_i >= 0.1} # Loop to remove every 10th record e = 0 d = 1 loop do x.length if e == (10 * d) d ++ e ++ else x = elements.select[e] e ++ end puts x puts "#{x.length} house in list, #{d} records skipped." CSV FILE ID,Street address,Town,Valuation date,Value 1,1 Northburn RD,WANAKA,1/1/2015,280000 2,1 Mount Ida PL,WANAKA,1/1/2015,280000 3,1 Mount Linton AVE,WANAKA,1/1/2015,780000 4,1 Kamahi ST,WANAKA,1/1/2015,155000 5,1 Kapuka LANE,WANAKA,1/1/2015,149000 6,1 Mohua MEWS,WANAKA,1/1/2015,560000 7,1 Kakapo CT,WANAKA,1/1/2015,430000 8,1 Mt Gold PL,WANAKA,1/1/2015,1260000 9,1 Penrith Park DR,WANAKA,1/1/2015,1250000 10,1 ATHERTON PL,WANAKA,1/1/2015,650000 11,1 WAIMANA PL,WANAKA,1/1/2015,780000 12,1 ROTO PL,WANAKA,1/1/2015,1470000 13,1 Toms WAY,WANAKA,1/1/2015,2230000 14,1 MULBERRY LANE,WANAKA,1/1/2015,415000 15,1 Range View PL,WANAKA,1/1/2015,300000 16,1 Clearview ST,WANAKA,1/1/2015,1230000 17,1 Clutha PL,WANAKA,1/1/2015,700000 18,1 Centre CRES,WANAKA,1/1/2015,295000 19,1 Valley CRES,WANAKA,1/1/2015,790000 20,1 Edgewood PL,WANAKA,1/1/2015,365000 21,1 HUNTER CRES,WANAKA,1/1/2015,335000 22,1 KOWHAI DR,WANAKA,1/1/2015,480000 23,1 RIMU LANE,WANAKA,1/1/2015,465000 24,1 CHERRY CT,WANAKA,1/1/2015,495000 25,1 COLLINS ST,WANAKA,1/1/2015,520000 26,1 AUBREY RD,WANAKA,1/1/2015,985000 27,1 EELY POINT RD,WANAKA,1/1/2015,560000 28,1 LINDSAY PL,WANAKA,1/1/2015,385000 29,1 WINDERS ST,WANAKA,1/1/2015,760000 30,1 Manuka CRES,WANAKA,1/1/2015,510000 31,1 WILEY RD,WANAKA,1/1/2015,420000 32,1 Baker GR,WANAKA,1/1/2015,820000 33,1 Briar Bank DR,WANAKA,1/1/2015,1260000 34,1 LAKESIDE RD,WANAKA,1/1/2015,440000 35,1 PLANTATION RD,WANAKA,1/1/2015,345000 36,1 Allenby PL,WANAKA,1/1/2015,640000 37,1 ROB ROY LANE,WANAKA,1/1/2015,380000 38,1 Ansted PL,WANAKA,1/1/2015,590000 39,1 Fastness CRES,WANAKA,1/1/2015,640000 40,1 APOLLO PL,WANAKA,1/1/2015,385000 41,1 AEOLUS PL,WANAKA,1/1/2015,370000 42,1 Peak View RDGE,WANAKA,1/1/2015,1750000 43,1 Moncrieff PL,WANAKA,1/1/2015,530000 44,1 Islington PL,WANAKA,1/1/2015,190000 45,1 Hidden Hills DR,WANAKA,1/1/2015,1280000 46,1 Weatherall CL,WANAKA,1/1/2015,425000 47,1 Terranova PL,WANAKA,1/1/2015,900000 48,1 Cliff Wilson ST,WANAKA,1/1/2015,1200000 49,1 TOTARA TCE,WANAKA,1/1/2015,460000 50,1 Koru WAY,WANAKA,1/1/2015,570000 51,1 Bovett PL,Wanaka,1/1/2015,495000 52,1 Pearce PL,Wanaka,1/1/2015,675000 53,1 Ironside DR,WANAKA,1/1/2015,570000 54,1 Bob Lee PL,WANAKA,1/1/2015,610000 55,1 Hogan LANE,WANAKA,1/1/2015,395000 56,1 ARDMORE ST,WANAKA,1/1/2015,1190000 57,1 Bullock Creek LANE,WANAKA,1/1/2015,11125000 58,1 DUNMORE ST,WANAKA,1/1/2015,1300000 59,1 Primary LANE,WANAKA,1/1/2015,430000 60,1 SYCAMORE PL,WANAKA,1/1/2015,720000 61,1 FAULKS TCE,WANAKA,1/1/2015,780000 62,1 Alpha CL,WANAKA,1/1/2015,500000 63,1 Coromandel ST,WANAKA,1/1/2015,530000 64,1 Niger ST,WANAKA,1/1/2015,475000 65,1 Maggies Way,WANAKA,1/1/2015,375000 66,1 Hollyhock LANE,QUEENSTOWN,1/1/2015,1080000 67,1 ELDERBERRY CRES,WANAKA,1/1/2015,1340000 68,1 Foxglove HTS,WANAKA,1/1/2015,2520000 69,1 MEADOWSTONE DR,WANAKA,1/1/2015,650000 70,1 OAKWOOD PL,WANAKA,1/1/2015,580000 71,1 MEADOWBROOK PL,WANAKA,1/1/2015,645000 72,1 Jessies CRES,WANAKA,1/1/2015,320000 73,1 Lansdown ST,WANAKA,1/1/2015,700000 74,1 Stonebrook DR,WANAKA,1/1/2015,640000 75,1 Hyland ST,WANAKA,1/1/2015,500000 76,1 TAPLEY PADDOCK,WANAKA,1/1/2015,720000 77,1 Homestead CL,WANAKA,1/1/2015,1750000 78,1 NORMAN TCE,WANAKA,1/1/2015,620000 79,1 Sunrise Bay DR,WANAKA,1/1/2015,3000000 80,1 LARCH PL,WANAKA,1/1/2015,570000 81,1 MILL END,WANAKA,1/1/2015,600000 82,1 Bills WAY,WANAKA,1/1/2015,750000 83,1 Heuchan LANE,WANAKA,1/1/2015,610000 84,1 SARGOOD DR,WANAKA,1/1/2015,455000 85,1 Frederick ST,WANAKA,1/1/2015,455000 86,1 Connell TCE,WANAKA,1/1/2015,600000 87,1 Soho ST,QUEENSTOWN,1/1/2015,320000 88,1 Hikuwai DR,ALBERT TOWN,1/1/2015,280000 89,1 Harrier LANE,WANAKA,1/1/2015,1000000 90,1 Ewing PL,WANAKA,1/1/2015,780000 91,1 Sherwin AVE,ALBERT TOWN,1/1/2015,440000 92,1 Hardie PL,WANAKA,1/1/2015,830000 93,1 Finch ST,ALBERT TOWN,1/1/2015,540000 94,1 Poppy LANE,ALBERT TOWN,1/1/2015,395000 95,1 Warbler LANE,ALBERT TOWN,1/1/2015,410000 96,1 Balneaves LANE,WANAKA,1/1/2015,250000 97,1 Mill Green,Arrowtown,1/1/2015,800000
require 'csv' elements = {} CSV.foreach("properties.csv", :headers => true, :header_converters => :symbol) do |row| elements[row.fields[0]] = Hash[row.headers[1..-1].zip(row.fields[1..-1])] end d = 0 e = 0 elements.delete_if do |key, value| e += 1 if e == 10 e = 0 d += 1 end e == 0 end puts "#{elements.length} house in list, #{d} records skipped." At the end of this, elements will have every 10th row removed, and d contains the number of rows removed.
Reading a line from a text file, splitting the string version of that line into two parts
Newbie learning Ruby. I am trying to take a txt file and on each line take the first 3 characters and assign them as a key, and the rest of the string as that's keys value. f = File.open("textfile.txt", "r") finalHash = {"Key" => "Data"} lineString = "" while f.gets != nil do lineString = f.gets part1 = lineString.slice(0, 2) part2 = lineString.slice(3, lineString.length) finalHash[:part1] = part2 end puts finalHash Any advice is appreciated!
the 2nd parameter of slice is the length, not the end-index, so change: part1 = lineString.slice(0, 2) to: part1 = lineString.slice(0, 3) If passed a start index and a length, returns a substring containing length characters starting at the index Also you don't need the second parameter here (this is not a bug though): part2 = lineString.slice(3, lineString.length) This is enough: part2 = lineString.slice(3)
Let's first create a file: text = <<_ Now is the time for all good Rubiests to come to the aid of their bowling team. _ FName = 'temp' File.write(FName, text) #=> 80 Now read the file a line at a time and construct the desired hash: File.foreach(FName).with_object({}) do |line, h| h[line.slice!(0,3)] = line.chomp end #=> {"Now"=>" is the", "tim"=>"e for all", "goo"=>"d Rubiests", # "to "=>"come to the", "aid"=>" of their", "bow"=>"ling team."} After reading the first line, h = { "Now"=>" is the" } line = "time for all\n" a = line.chomp #=> "time for all" b = a.slice!(0,3) #=> "tim" a #=> "e for all" h[b] = a #=> "e for all" h #=> {"Now"=>" is the", "tim"=>"e for all"} No direction is given if a line contains fewer than three characters. That may be something to consider.
lines = File.open("textfile.txt").read.split("\n") hsh = {} lines.each do |line| next if line == "" hsh[line[0..2]] = line[3..-1] end using your method of slowly nibbling at the file f = File.open("textfile.txt") hsh = {} loop do x = f.gets break unless x hsh[x[0..2]] = x[3..-1] end
Borrowing #Cary's sample file... text = <<_ Now is the time for all good Rubiests to come to the aid of their bowling team. _ FName = 'temp' File.write(FName, text) Now the file exists. Convert it to a 2 dimensional array. This array is trivially converted to a hash File.foreach(FName).map{|x| [x.slice!(0,3), x]}.to_h => {"Now"=>" is the\n", "tim"=>"e for all\n", "goo"=>"d Rubiests\n", "to "=>"come to the\n", "aid"=>" of their\n", "bow"=>"ling team.\n"}
Here you go : Sample data: [zatcsv]$ cat foo.txt TOK UPDATE DATE SHOT TIME AUXHEAT PHASE STATE PGASA PGASZ BGASA BGASZ BGASA2 BGASZ2 PIMPA PIMPZ PELLET RGEO RMAG AMIN SEPLIM XPLIM KAPPA DELTA INDENT AREA VOL CONFIG IGRADB WALMAT DIVMAT LIMMAT EVAP BT IP VSURF Q95 BEPMHD BETMHD BEPDIA NEL DNELDT ZEFF PRAD POHM ENBI PINJ BSOURCE PINJ2 BSOURCE2 COCTR PNBI ECHFREQ ECHMODE ECHLOC PECH ICFREQ ICSCHEME ICANTEN PICRH LHFREQ LHNPAR PLH IBWFREQ PIBW TE0 TI0 WFANI WFICRH MEFF ISEQ WTH WTOT JET 20031201 20001006 53521 1.000E+01 NBIC HSELM TRANS 2.000E+00 1.000E+00 2 1 0 0 1.658E+01 8.152E+00 NONE 2.888E+00 HEEH OIJ OIJJ 3.047E+00 9.807E-01 2.924E-02 7.304E-02 1.572E+00 1.781E-01 0.000E+00 4.572E+00 8.161E+01 LSN 1 IN/ 2.000E+06 1.013E-01 6.001E+00 1.053E+00 9.252E-01 1.128E+00 3.106E+19 3.106E+19 6.612E+00 4.515E+06 5.122E+04 1.000E+05 1.466E+07 771706 0.000E+00 652114 1.000E+00 1.420E+07 -9.999E-09 NONE NONE 0.000E+00 5.100E+07 HMIN MONOPOLE 4.027E+06 3.700E+09 1.840E+00 2.000E+06 -9.999E-09 0.000E+00 9.295E+03 1.373E+04 6.913E-01 7.319E+05 2.000E+00 NONE 3.715E+06 5.381E+06 1.282E+06 1.297E+07 1.210E+07 something like this will do it for you : [za csv]$cat text_to_hash.rb #!/usr/bin/env ruby file_dir = "/dir/to_folder/foo.txt" thehash = Hash.new line = File.read(file_dir).each_line do |line| thehash[ key = line.slice(0..2)] = val = line.slice(3..-1) thehash.each { |k , val| puts " Key: #{key} Value: #{val}"} end Outputs: [za csv]$ ./text_to_hash.rb Key: TOK Value: UPDATE DATE SHOT TIME AUXHEAT PHASE STATE PGASA PGASZ BGASA BGASZ BGASA2 BGASZ2 PIMPA Key: PIM Value: PZ PELLET RGEO RMAG AMIN SEPLIM XPLIM KAPPA DELTA INDENT AREA VOL CONFIG IGRADB WALMAT DIVMAT LIMMAT EVAP Key: ECH Value: MODE ECHLOC PECH ICFREQ ICSCHEME ICANTEN PICRH LHFREQ LHNPAR PLH IBWFREQ PIBW TE0 TI0 WFANI WFICRH MEFF ISEQ WTH WTOT Key: JET Value: 20031201 20001006 53521 1.000E+01 NBIC HSELM TRANS 2.000E+00 1.000E+00 2 1 0 0 1.658E+01 8.152E+00 NONE 2.888E+00 Key: HEE Value: H OIJ OIJJ 3.047E+00 9.807E-01 2.924E-02 7.304E-02 1.572E+00 1.781E-01 0.000E+00 4.572E+00 8.161E+01 LSN 1 IN/ Key: 2.0 Value: 00E+06 1.013E-01 6.001E+00 1.053E+00 9.252E-01 1.128E+00 3.106E+19 3.106E+19 6.612E+00 4.515E+06 5.122E+04 1.000E+05 1.466E+07 Key: 771 Value: 706 0.000E+00 652114 1.000E+00 1.420E+07 -9.999E-09 NONE NONE 0.000E+00 5.100E+07 HMIN MONOPOLE 4.027E+06 3.700E+09 1.840E+00 Key: 2.0 Value: 00E+06 -9.999E-09 0.000E+00 9.295E+03 1.373E+04 6.913E-01 7.319E+05 2.000E+00 NONE 3.715E+06 5.381E+06 1.282E+06 1.297E+07 1.210E+07 Key: 4.4 Value: 45E-01 2.194E-01
How to extract string from large file only if specific string appears previous using Ruby?
I am trying to extract information from a large file and cannot figure out how to extract strings from file lines only when a previous line in the same record within the file has been matched by regex. An example of one record in the file is as follows: *NEW RECORD RECTYPE = D MH = Informed Consent AQ = ES HI LJ PX SN ST ENTRY = Consent, Informed MN = N03.706.437.650.312 MN = N03.706.535.489 FX = Disclosure FX = Mental Competency FX = Therapeutic Misconception FX = Treatment Refusal ST = T058 ST = T078 AN = competency to consent: coordinate IM with MENTAL COMPETENCY (IM) PI = Jurisprudence (1966-1970) PI = Physician-Patient Relations (1966-1970) MS = Voluntary authorization, by a patient or research subject, etc,... This file contains over 20,000 records like this example. I want to identify a small percent of those records using the "MH" field. In this example, I want to find "Informed Consent", and then use regex to extract the information in the FX, AN, and MS fields only within that record. So far, I have opened the file, accessed the hash that the MH terms are stored in, and been able to extract those terms from the records in the file. I also have a functioning regex that identifies the content in the "FX" field. File.open('mesh_descriptor.bin').each do |file_line| file_line = file_line.chomp # read each key of candidate_descriptor_keys candidate_descriptor_keys.each do |cand_term| if file_line =~ /^MH\s=\s(#{cand_term})$/ mesh_header = $1 puts "MH from Mesh Descriptor file is: #{mesh_header}" if file_line =~ /^FX\s=\s(.*)$/ see_also = $1 puts " See_Also from Descriptor file is: #{see_also}" end end end end The hash contains the following MH (keys): candidate_descriptor_keys = ["Body Weight", "Obesity", "Thinness", "Fetal Weight", "Overweight"] I had success extracting "FX" when I put the statement outside of the "if" statement to extract "MH", but all of the "FX" from the whole file were retrieved - not what I need. I thought putting the "if" statement for "FX" within the previous "if" statement would restrict the results to only those found when the first statement is true, but I am getting no results (also no errors) with this strategy. What I would like as a result is: > Informed Consent > Disclosure > Mental Competency > Therapeutic Misconception > Treatment Refusal as well as the strings within the "AN" and "MS" fields for only those records matching "MH". Any suggestions would be helpful!
I think this may be what you are looking for, but if not, let me know and I will change it. Look especially at the very end to see if that is the sort of output (for input having two records, both with a "MH" field) you want. I will also add a "explanation" section at the end once I have understood your question correctly. I have assumed that each record begins *NEW_RECORD and you wish to identify all lines beginning "MH" whose field is one of the elements of: candidate_descriptor_keys = ["Body Weight", "Obesity", "Thinness", "Informed Consent"] and for each match, you would like to print the contents of the lines for the same record that begin with "FX", "AN" and "MS". Code NEW_RECORD_MARKER = "*NEW RECORD" def getem(fname, candidate_descriptor_keys) line = 0 found_mh = false File.open(fname).each do |file_line| file_line = file_line.strip case when file_line == NEW_RECORD_MARKER puts # space between records found_mh = false when found_mh == false candidate_descriptor_keys.each do |cand_term| if file_line =~ /^MH\s=\s(#{cand_term})$/ found_mh = true puts "MH from line #{line} of file is: #{cand_term}" break end end when found_mh ["FX", "AN", "MS"].each do |des| if file_line =~ /^#{des}\s=\s(.*)$/ see_also = $1 puts " Line #{line} of file is: #{des}: #{see_also}" end end end line += 1 end end Example Let's begin be creating a file, starging with a "here document that contains two records": records =<<_ *NEW RECORD RECTYPE = D MH = Informed Consent AQ = ES HI LJ PX SN ST ENTRY = Consent, Informed MN = N03.706.437.650.312 MN = N03.706.535.489 FX = Disclosure FX = Mental Competency FX = Therapeutic Misconception FX = Treatment Refusal ST = T058 ST = T078 AN = competency to consent PI = Jurisprudence (1966-1970) PI = Physician-Patient Relations (1966-1970) MS = Voluntary authorization *NEW RECORD MH = Obesity AQ = ES HI LJ PX SN ST ENTRY = Obesity MN = N03.706.437.650.312 MN = N03.706.535.489 FX = 1st FX FX = 2nd FX AN = Only AN PI = Jurisprudence (1966-1970) PI = Physician-Patient Relations (1966-1970) MS = Only MS _ If you puts records you will see it is just a string. (You'll see that I shortened two of them.) Now write it to a file: File.write('mesh_descriptor', records) If you wish to confirm the file contents, you could do this: puts File.read('mesh_descriptor') We also need to define define the array candidate_descriptor_keys: candidate_descriptor_keys = ["Body Weight", "Obesity", "Thinness", "Informed Consent"] We can now execute the method getem: getem('mesh_descriptor', candidate_descriptor_keys) MH from line 2 of file is: Informed Consent Line 7 of file is: FX: Disclosure Line 8 of file is: FX: Mental Competency Line 9 of file is: FX: Therapeutic Misconception Line 10 of file is: FX: Treatment Refusal Line 13 of file is: AN: competency to consent Line 16 of file is: MS: Voluntary authorization MH from line 18 of file is: Obesity Line 23 of file is: FX: 1st FX Line 24 of file is: FX: 2nd FX Line 25 of file is: AN: Only AN Line 28 of file is: MS: Only MS
Lua: how use all tables in table
positions = { --table 1 [1] = {pos = {fromPosition = {x=1809, y=317, z=8},toPosition = {x=1818, y=331, z=8}}, m = {"100 monster"}}, --table 2 [2] = {pos = {fromPosition = {x=1809, y=317, z=8},toPosition = {x=1818, y=331, z=8}}, m = {"100 monster"}}, -- table3 [3] = {pos = {fromPosition = {x=1809, y=317, z=8},toPosition = {x=1818, y=331, z=8}}, m = {"100 monster"}} } tb = positions[?]--what need place here? for _,x in pairs(tb.m) do --function for s = 1, tonumber(x:match("%d+")) do pos = {x = math.random(tb.pos.fromPosition.x, tb.pos.toPosition.x), y = math.random(tb.pos.fromPosition.y, tb1.pos.toPosition.y), z = tb.pos.fromPosition.z} doCreateMonster(x:match("%s(.+)"), pos) end end Here the problem, i use tb = positions[1], and it only for one table in "positions" table. But how apply this function for all tables in this table?
I don't know Lua very well but you could loop over the table: for i = 0, table.getn(positions), 1 do tb = positions[i] ... end Sources : http://lua.gts-stolberg.de/en/schleifen.php and http://www.lua.org/pil/19.1.html
You need to iterate over positions with a numerical for. Note that, unlike Antoine Lassauzay's answer, the loop starts at 1 and not 0, and uses the # operator instead of table.getn (deprecated function in Lua 5.1, removed in Lua 5.2). for i=1,#positions do tb = positions[i] ... end
use the pairs() built-in. there isn't any reason to do a numeric for loop here. for index, position in pairs(positions) do tb = positions[index] -- tb is now exactly the same value as variable 'position' end
Ruby data extraction from a text file
I have a relatively big text file with blocks of data layered like this: ANALYSIS OF X SIGNAL, CASE: 1 TUNE X = 0.2561890123390808 Line Frequency Amplitude Phase Error mx my ms p 1 0.2561890123391E+00 0.204316425208E-01 0.164145385871E+03 0.00000000000E+00 1 0 0 0 2 0.2562865535359E+00 0.288712798671E-01 -.161563284233E+03 0.97541196785E-04 1 0 0 0 (they contain more lines and then are repeated) I would like first to extract the numerical value after TUNE X = and output these in a text file. Then I would like to extract the numerical value of LINE FREQUENCY and AMPLITUDE as a pair of values and output to a file. My question is the following: altough I could make something moreorless working using a simple REGEXP I'm not convinced that it's the right way to do it and I would like some advices or examples of code showing how I can do that efficiently with Ruby.
Generally, (not tested) toggle=0 File.open("file").each do |line| if line[/TUNE/] puts line.split("=",2)[-1].strip end if line[/Line Frequency/] toggle=1 next end if toggle a = line.split puts "#{a[1]} #{a[2]}" end end go through the file line by line, check for /TUNE/, then split on "=" to get last item. Do the same for lines containing /Line Frequency/ and set the toggle flag to 1. This signify that the rest of line contains the data you want to get. Since the freq and amplitude are at fields 2 and 3, then split on the lines and get the respective positions. Generally, this is the idea. As for toggling, you might want to set toggle flag to 0 at the next block using a pattern (eg SIGNAL CASE or ANALYSIS)
file = File.open("data.dat") #tune_x = #frequency = #amplitude = [] file.each_line do |line| tune_x_scan = line.scan /TUNE X = (\d*\.\d*)/ data_scan = line.scan /(\d*\.\d*E[-|+]\d*)/ #tune_x << tune_x_scan[0] if tune_x_scan #frequency << data_scan[0] if data_scan #amplitude << data_scan[0] if data_scan end
There are lots of ways to do it. This is a simple first pass at it: text = 'ANALYSIS OF X SIGNAL, CASE: 1 TUNE X = 0.2561890123390808 Line Frequency Amplitude Phase Error mx my ms p 1 0.2561890123391E+00 0.204316425208E-01 0.164145385871E+03 0.00000000000E+00 1 0 0 0 2 0.2562865535359E+00 0.288712798671E-01 -.161563284233E+03 0.97541196785E-04 1 0 0 0 ANALYSIS OF X SIGNAL, CASE: 1 TUNE X = 1.2561890123390808 Line Frequency Amplitude Phase Error mx my ms p 1 1.2561890123391E+00 0.204316425208E-01 0.164145385871E+03 0.00000000000E+00 1 0 0 0 2 1.2562865535359E+00 0.288712798671E-01 -.161563284233E+03 0.97541196785E-04 1 0 0 0 ANALYSIS OF X SIGNAL, CASE: 1 TUNE X = 2.2561890123390808 Line Frequency Amplitude Phase Error mx my ms p 1 2.2561890123391E+00 0.204316425208E-01 0.164145385871E+03 0.00000000000E+00 1 0 0 0 2 2.2562865535359E+00 0.288712798671E-01 -.161563284233E+03 0.97541196785E-04 1 0 0 0 ' require 'stringio' pretend_file = StringIO.new(text, 'r') That gives us a StringIO object we can pretend is a file. We can read from it by lines. I changed the numbers a bit just to make it easier to see that they are being captured in the output. pretend_file.each_line do |li| case when li =~ /^TUNE.+?=\s+(.+)/ print $1.strip, "\n" when li =~ /^\d+\s+(\S+)\s+(\S+)/ print $1, ' ', $2, "\n" end end For real use you'd want to change the print statements to a file handle: fileh.print The output looks like: # >> 0.2561890123390808 # >> 0.2561890123391E+00 0.204316425208E-01 # >> 0.2562865535359E+00 0.288712798671E-01 # >> 1.2561890123390808 # >> 1.2561890123391E+00 0.204316425208E-01 # >> 1.2562865535359E+00 0.288712798671E-01 # >> 2.2561890123390808 # >> 2.2561890123391E+00 0.204316425208E-01 # >> 2.2562865535359E+00 0.288712798671E-01
You can read your file line by line and cut each by number of symbol, for example: to extract tune x get symbols from 10 till 27 on line 2 to extract LINE FREQUENCY get symbols from 3 till 22 on line 6+n