1

For my program input is a csv file with some variable names and their values.

| var name       | value          |
| --------       | -------------- |
| a.b            | 345            |
| a.c._0_.field1 | 322            |
| a.c._0_.field2 | 5              |
| a.c._1_.field1 | 32             |
| a.c._1_.field2 | 50             |

In my code, I want to read this file and create struct variables with value mentioned in the file with following constraints.

  1. None of the variables' names are known. It should be thus create them dynamically
  2. All the sub structs are separated by .
  3. And in case of array, different indexes are mentioned with _%d%_.

In above case, struct a will have data:

a.b = 345
a.c(1).field1 = 322
a.c(1).field2 = 5
a.c(2).field1 = 32
a.c(2).field2 = 50

How can I create struct named a and save to mat file? I could do it using eval however, since it is not recommended, I was wondering if same could be achieved using setfield getfield

Adriaan
  • 17,741
  • 7
  • 42
  • 75
Anonymous
  • 336
  • 3
  • 23
  • 1
    AFAIK you can't create `a` without using `eval`. Otherwise, all fields can be set as usual; simply read in your file, grab the string in the first column, `strplit('.')`, then use each string as a field name: `my_struct.splitted_string(1)` etc. Given you changed the CSV after [your previous question](https://stackoverflow.com/q/72348172/5211833), I suspect this is an [XY problem](https://meta.stackexchange.com/q/66377/325771). There might well be a better way to get your data into MATLAB than creating this CSV file. – Adriaan May 24 '22 at 07:28
  • 2
    You need to parse the string, and convert it to indexing operations. This is not hard. The hard part is creating a variable with a name specified in the CSV file. It can be done with `eval`, but it's just a really bad idea, for many reasons. I suggest instead that you create a struct `data`, containing all these variables: `data.a.b`, `.data.a.c(1).field1`, etc. – Cris Luengo May 24 '22 at 07:28
  • 2
    Create the indexing operations using `substruct` and `subsasgn`. – Cris Luengo May 24 '22 at 07:31
  • 1
    Could you please [edit] your question to give more background on how you create your CSV in the first place and what you want to do with that data in MATLAB? It looks like you have control over how you create your CSV, which makes me think that you could structure your data transfer a lot more efficient than by trying to create variables based on text in a separate file. – Adriaan May 24 '22 at 07:36
  • I do not have control over creating CSV file. My only issue is I cannot understand how to do indexing. Since, I finally want to save it to mat file, I am okay with creating `data` struct. and when I save it like `save('out.mat', '-struct', 'data')` a gets stored as it is. – Anonymous May 24 '22 at 07:51
  • Turns out that nesting fields in structures is more difficult than I assumed. `data.('splitted_str{1}')` can add one field, but a field within a field isn't easy apparently. You might get around that by creating your fields one by one, filling them with dummy data, which is deleted afterwards. – Adriaan May 24 '22 at 09:31
  • The best way of doing this is with `eval`. But I think you should try to simply change your goal. Store this information somehow else – Ander Biguri May 24 '22 at 10:34

1 Answers1

2

I'll assume here you've read your file already into MATLAB here; you can use strsplit() to split your variable name on the dot, check whether the entry corresponds to a number or field name, and create your struct with those. You can use a substruct(), in combination with subsref() or subsasgn(), to do your indexing:

data = struct;  % Initialise your final structure
% Insert a loop here over all your rows
parts = strsplit(my_str, '.');  % split your string
indx = struct;
for ii = 1:numel(parts)
    if parts{ii}(1) ~= '_' || parts{ii}(end) ~= '_'
        indx(ii).type = '.';
        indx(ii).subs = parts{ii};
    else
        indx(ii).type = '()';
        indx(ii).subs = {str2double(parts{ii}(2:end-1))};
    end
end
data = subsasgn(data, indx, my_data);

I do think this is an XY problem. There's probably a better way to export your data from whatever you used to create the CSV and a better way to load it into MATLAB for later use. Please do explain how you create your CSV in the first place and what you want to do with the data in MATLAB (or in your .mat file). Repackaging CSV files to .mat files just for the thrill of it will hardly be your goal. Thus, please ask about your problem (X), rather than your attempted solution (Y), in order to get more helpful responses.

Adriaan
  • 17,741
  • 7
  • 42
  • 75