how to extract a field from a nested structure, modify it, and write it back

15 visualizaciones (últimos 30 días)
I have a structure (provided in a thrid party script) with a large number of fields of different types, call it ALL
One of the fields of ALL is a [1x1209 struct], call it EVNT
EVNT is a struct with 4 fields of length 1209:
dur
typ
lat
ure
Each of the above is an array of different type. I am not sure how to determine what the type of each of the above 4 fields is. I can see that the field I wish to modify, 'typ' is text, and the other three are numeric. I wish to modify the "typ" field, either in place, or by copying it, modifying it, and writing it back into the main struct, then saving that to a new file.
I am very confused about the indexing syntax to do this. Can you please advise? I tried this based on reading about the setfield command and got an error message.
>> ALLEEG=setfield(ALLEEG,'EVNT','typ',{2},'test')
Error using setfield (line 59)
Scalar structure required for this assignment.
-Jeff

Respuestas (2)

Stephen23
Stephen23 el 7 de Jul. de 2021
Editada: Stephen23 el 7 de Jul. de 2021
As this information is missing in your question, I will assume that ALL is a scalar structure.
fun = @(n)struct('dur',n, 'typ','X', 'lat',n*n, 'ure',sqrt(n));
ALL.BLAH = 0;
ALL.EVNT = arrayfun(fun,1:1209)
ALL = struct with fields:
BLAH: 0 EVNT: [1×1209 struct]
ALL.EVNT(1) % checking the field EVNT of one element of ALL
ans = struct with fields:
dur: 1 typ: 'X' lat: 1 ure: 1
Here is how you can access the data in the 'typ' field, for example for the 3rd element of ALL:
Method one: indexing:
typ = ALL.EVNT(2).typ % original value
typ = 'X'
ALL.EVNT(2).typ = 'test2';
ALL.EVNT(2).typ % checking new value
ans = 'test2'
Method two: GETFIELD/SETFIELD (less efficient):
typ = getfield(ALL,{1},'EVNT',{3},'typ') % original value
typ = 'X'
ALL = setfield(ALL,{1},'EVNT',{3},'typ', 'test3');
typ = getfield(ALL,{1},'EVNT',{3},'typ') % checking new value
typ = 'test3'
Note that GETFIELD and SETFIELD functions require either zero indices or all indices: you cannot just supply one index and omit all of the other indices.

Schoepfloeffel
Schoepfloeffel el 22 de Nov. de 2023
Hello, I want to add to the discussion by another method to modify the fields in the array struct "in place"
We setup a struct array - within a nested struct resides. We want to modify all fields at once or by slice operation of our struct array. How?
fun = @(n)struct('dur',n, 'typ','X', 'lat',n*n, 'ure',sqrt(n), 'nested_struct', struct('field1', "a_string", 'field2', n^exp(1)));
ALL.BLAH = 0;
ALL.EVNT = arrayfun(fun,1:1209);
We can use arrayfun to apply the setfield function to every value in the struct array and return the struct array within one line. We can also use slicing operations to make it easier to change only certain fields
[ALL.EVNT(1).typ; ALL.EVNT(2).typ] %previous value
ans = 2×1 char array
'X' 'X'
ALL.EVNT = arrayfun(@(x) setfield(x, 'typ', 'my_new_type'), ALL.EVNT); %set specified field in each struct (1209 fields)
ALL.EVNT(1:3) = arrayfun(@(x) setfield(x, 'typ', 'my_newest_type'), ALL.EVNT(1:3)); %set specified field in slice of struct array (changes field in struct 1 to 3)
[ALL.EVNT(1).typ; ALL.EVNT(2).typ] %after manipulation
ans = 2×14 char array
'my_newest_type' 'my_newest_type'
We can use the same syntax on higher order nested structures. We just traverse the structs with setfield for all values in the array (or slice of array). I think it is easier to work with this syntax instead of looping.
ALL.EVNT = arrayfun(@(x) setfield(x, 'nested_struct', 'field1', "a_new_string"), ALL.EVNT); %also works with deeply nested structs
You can try out to apply other built-in functions to all field values within the nested struct and return the whole struct array. I use setfield as a function handle the indexing. If you wish to be more dynamic, I advise to write your own function and make your own function handle to make these kind of manipulations easier. Here an example to cast the string value to a char value.
disp(unique(arrayfun(@(x) class(x.nested_struct.field1), ALL.EVNT, 'UniformOutput', false))) %checking the type --> 'char'
{'string'}
ALL.EVNT = arrayfun(@(x) setfield(x, 'nested_struct', 'field1', char(x.nested_struct.field1)), ALL.EVNT); %cast string to char
disp(unique(arrayfun(@(x) class(x.typ), ALL.EVNT, 'UniformOutput', false)))
{'char'}
Hope this helps with manipulting the data structures easier.
BR

Categorías

Más información sobre Structures en Help Center y File Exchange.

Etiquetas

Productos


Versión

R2021a

Community Treasure Hunt

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

Start Hunting!

Translated by