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

Resources