Is it possible to create a nested structure with dynamic field names?

I am parsing an ascii data header file with obnoxiously human unreadable field names like:
structureName.manufacturer.modelNumber.serialNumber.hardwarePartID(6).hardwareAddresses(24).featureList(274).licensed = "1"
There are thousands of lines, and since this needs to be inspected by a human from time to time, I am reorganizing the information into a more readable and workable format, but I have run into a problem. I need only certain lines of data, and only if those lines exist. I have settled upon making a variable list of parameters I need (based on the specific application), and I have read the ascii text into structures with the same field names. The problem is when I have to assign these parsed parameter values into my new (readable) structure, I have to step through the list of field names.
I would like to be able to use dynamic field naming to make the assignments. For instance,
fieldname = 'charles'; %this name would change with every step, and itself will be nested as well
structureName.(fieldname) = parsedStructure.(manufacturer).(modelNumber). ... %etc
However, this version of dot indexing (right side dynamic naming) is not supported. Neither is:
structureName.(fieldname) = parsedStructure.(manufacturer.modelNumber) ... %etc
And, of course, the first thing I tried was using the dotted fieldnames as text:
parsedField = 'manufacturer.modelNumber.whateverNonsenseComesAfterThis';
structureName.(fieldname) = parsedStructure.(parsedField);
But using nested field names isn't supported either. Or at least, I haven't been able to figure out how to do it.
I can make it work with an eval call, but there are several reasons why that isn't a good idea, and I'd rather not stick with that solution. Basically, what I need to do is be able to step through a list of (hundreds of) required parameters, and for those that exist in the data, extract them into my new structure.
Any ideas?

6 commentaires

I feel silly.
Like a dummy, I tried to employ MATLAB's new used of double quotes to reference the dynamic field names like they do in the examples for dynamic field naming. That doesn't work. Single quotes do. I've been writing MATLAB code since 1991, and this is literally the first time I've attempted using double quotes in my code, and the first time I've had to resort to asking a question here. I can't believe I didn't just fall back to what I know best. I really, really hate that they have decided to confuse everything with limited use of double quotes.Ugh.
Thanks for holding a mirror up to my face!
"I tried to employ MATLAB's new used of double quotes to reference the dynamic field names like they do in the examples for dynamic field naming. That doesn't work"
S.A = pi,
S = struct with fields:
A: 3.1416
S.("A")
ans = 3.1416
Both scalar strings and char vectors should work in dynamic field name indexing.
a = struct('b', struct('c', 5));
s = "b";
c = 'c';
y = a.(s).(c)
y = 5
Can you show a small example where you tried to use a scalar string and it didn't work? Did you receive an error message, and if so what was the full and exact text of that error?
I could see this failing if you had a non-scalar string, but the error message seems to fairly clearly identify the cause of the error.
d = [s s]
d = 1×2 string array
"b" "b"
y = a.(d)
Dynamic field or property name must be a string scalar or character vector.
d is a string but it's not scalar.
OK, let me try and state the problem a different way. This is the eval line I'm trying to replace. The fieldName arguments are the names of nested fields that will change with each call. Both the number of nests and the names will change. Neither list of names will be the same for every run, so both the parsed and assigned field names have to be fully dynamic.
I can split the names, of course, but I can't think of a way to compose a statement that does this without an eval. Is there a technique I have overlooked?
eval(['base.', fieldName, ' = hdr.', parsedFieldName, ';']);
As an example, fieldName might be 'one" or might be 'one.two' or 'sam.steve.jeff' or any one of hundreds of other possibilities. And of course, parsedFieldName will have the same variability. There is no way to predict the degree of nesting (though, the base will be three or less, and the hdr will be nine or less). There is also no way to predict which names will be used or what they will even be. Different fields have different numbers of subfields. Some will have only one, and others could reach many dozens of subfields.
Say I split the field names into a cell. How can I form an assignemt statement from this or another way to break down the problem?
Does that help?
"Is there a technique I have overlooked?"
As I wrote in my answer, you can use GETFIELD(), probably with a comma-separated list:
And on the LHS basic dynamic fieldname:
S.A.B.C = pi;
F = 'A.B.C';
C = split(F,'.');
Z.('new') = getfield(S,C{:})
Z = struct with fields:
new: 3.1416
I didn't overlook that. You can't get or set nested fieldnames with those functions.
f = 'one.two.three';
fSplit = split(f, '.');
hdr = setfield(hdr, fSplit, 1);
%This isn't supported, either:
hdr = setfield(hdr, f, 1);

Connectez-vous pour commenter.

 Réponse acceptée

"However, this version of dot indexing (right side dynamic naming) is not supported."
Lets try it right now:
S.A.B.C = pi;
S.('A').('B').('C')
ans = 3.1416
If you want to mix in subscript indexing as well then you can use GETFIELD() / SETFIELD():
S.A.B(2).C = exp(1);
getfield(S,{1},'A',{1},'B',{2},'C')
ans = 2.7183
Another option is to use SUBSREF() / SUBSASGN():
X = substruct('.','A', '.','B', '()',{2}, '.','C');
subsref(S,X)
ans = 2.7183
Obviously you just need to use STRSPLIT() or similar to get each level of the structure heirarchy from your single piece of text, and handle those subscript indices correctly. You might find cell arrays and comma-separated lists very useful:

Plus de réponses (0)

Catégories

Produits

Version

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by