4
$\begingroup$

Lets assume I have a .txt file with the following content:

New entry.
R 445.24
Z 4713.5
Data
-218.474 -1127.02 261.511
-268.049 -1384.29 245.665
-275.05 -1420.62 243.428
-285.106 -1472.8 240.214
-301.545 -1558.11 234.959
-366.24 -1893.84 214.281
-380.351 -1967.07 209.771
-436.455 -2258.21 191.838
-493.221 -2552.79 173.694
-652.165 -3377.61 122.891
-724.069 -3750.75 99.9089
-806.379 -4177.89 73.6002
Result -85.4974 -436.954 304.014
New entry.
R 2600
Z 3428.47
Data
-218.474 -1127.02 261.511
-268.049 -1384.29 245.665
-275.05 -1420.62 243.428
-285.106 -1472.8 240.214
-301.545 -1558.11 234.959
-366.24 -1893.84 214.281
-380.351 -1967.07 209.771
-436.455 -2258.21 191.838
-493.221 -2552.79 173.694
-652.165 -3377.61 122.891
-724.069 -3750.75 99.9089
-806.379 -4177.89 73.6002
Result -493.221 -2552.79 173.694
...

I would now like to read in the values and save the R, Z, Data and Result values and keep them connected so I can access them easily. The data and result entries are 3D vectors and while Result, R and Z always have exactly one entry, the number of entries in Data can vary. What is the best way to do this? Thanks!

$\endgroup$
6
$\begingroup$

Assuming I understand your data structure correctly, you could do something based on the following:

SplitBy[Import["file.txt", "List"], StringMatchQ["New entry."]][[2 ;; ;; 2]]

This imports the file as a list of strings, and then splits the list into sublists everytime an element is "New Entry.". You can then take every other element (starting with the second element).

I would personally try to put this into a collection of Associations. If you have a really large number of data points this might not be the best way, but it should still be illustrative. Here is a helper function:

readBlock[
  r_List] := <|
    "R" -> Interpreter["Number"]@StringExtract[r[[1]], 2], 
    "Z" -> Interpreter["Number"]@StringExtract[r[[2]], 2], 
    "Data" -> Interpreter[DelimitedSequence["Number"]]/@r[[4 ;; -2]], 
    "Result" -> Interpreter["Number"] /@ StringExtract[r[[-1]], 2 ;; 4]
     |> 

which can be used like so:

readBlock /@ (SplitBy[Import["file.txt", "List"],StringMatchQ["New entry."]][[2 ;; ;; 2]])

(* {<|"R" -> 445.24, "Z" -> 4713.5, 
  "Data" -> {{-218.474, -1127.02, 261.511}, {-268.049, -1384.29, 
     245.665}, {-275.05, -1420.62, 243.428}, {-285.106, -1472.8, 
     240.214}, {-301.545, -1558.11, 234.959}, {-366.24, -1893.84, 
     214.281}, {-380.351, -1967.07, 209.771}, {-436.455, -2258.21, 
     191.838}, {-493.221, -2552.79, 173.694}, {-652.165, -3377.61, 
     122.891}, {-724.069, -3750.75, 99.9089}, {-806.379, -4177.89, 
     73.6002}}, 
  "Result" -> {-85.4974, -436.954, 304.014}|>, <|"R" -> 2600, 
  "Z" -> 3428.47, 
  "Data" -> {{-218.474, -1127.02, 261.511}, {-268.049, -1384.29, 
     245.665}, {-275.05, -1420.62, 243.428}, {-285.106, -1472.8, 
     240.214}, {-301.545, -1558.11, 234.959}, {-366.24, -1893.84, 
     214.281}, {-380.351, -1967.07, 209.771}, {-436.455, -2258.21, 
     191.838}, {-493.221, -2552.79, 173.694}, {-652.165, -3377.61, 
     122.891}, {-724.069, -3750.75, 99.9089}, {-806.379, -4177.89, 
     73.6002}}, "Result" -> {-493.221, -2552.79, 173.694}|>} *)

If you wanted, you could make this into one function that imports and does the processing.

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.