0

I'm trying to exctract some data from a nested structure in a recursive manner. First, I know that this has a field (values) which repeats itself inside the nested structure. Secondly I know that the structure which has those values has only structures as fields. In the below code I've tried to acces the structure.values by searching if my current structure has a field named values. If it has, I put .values at the end of my structure name. If it doesn't have this field, I verify if all the fields are structures. If they are, it means that I will have to consider them further and to extract the values from each one. If the fields are not structures, it means that they are values and I save them into a new simplified structure. Example of fields that I want: S.values.model1.values.mission.values.(alt/list). Currently, with the below code I'm only able to get the values from one field and then I get an error and don't know how to approach further.

Code example:

clear all
clc

S=struct()

S.case='1';
S.type='A';
S.values.model1.case='2'
S.values.model1.type='C'
S.values.model1.values.mission.case='3'
S.values.model1.values.mission.type='D'
S.values.model1.values.mission.values.alt='none'
S.values.model1.values.mission.values.list=2
S.values.model1.values.mission.values.parameter=4

S.values.model1.values.phase.case='4'
S.values.model1.values.phase.type='A'
S.values.model1.values.phase.values.num='all'
S.values.model1.values.phase.values.eq=2
S.values.model1.values.phase.values.unit=4

S.values.model1.values.analysis.case='1'
S.values.model1.values.phase.type='A'
S.values.model1.values.phase.values.nump1.list='all'
S.values.model1.values.phase.values.nump1.table='four'
S.values.model1.values.phase.values.nump1.mean=0

S.values.model1.values.phase.values.nump2.list='none'
S.values.model1.values.phase.values.nump2.table='three';
S.values.model1.values.phase.values.nump2.mean=1


s=S.values.model1;
names=fieldnames(s);
nnames=numel(names);

newStruct={};
[valsi,newstructi]=extractValues(names,s,nnames,newStruct)


function [vals,newStruct]=extractValues(names,vals,nnames,newStruct)
if any(strcmp(names,'values'))
    vals=vals.('values');
    names=fieldnames(vals)
    nnames=numel(names)
    
    [vals,newStruct]=extractValues(names,vals,nnames,newStruct);
   
end


for j=1:nnames
    
    value(j)=isstruct((vals.(names{j})));
end

if all(value)
    
    
    for k=1:nnames
        
        vals=(vals.(names{k}));
        names=fieldnames(vals);
        nnames=numel(names);
        
        [vals,newStruct]=extractValues(names,vals,nnames,newStruct);
        
    end
    
else
    
    for j=1:nnames
        
        value=(vals.(names{j}));
        newStruct.(names{j})=value;
    end
end
end
Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
Cassius
  • 5
  • 2
  • `clear all` is almost never needed. Use `clear` by itself to clear all the variables from the workspace. `clear all` also clears loaded function definitions and other things that will need to be reloaded, slowing down code execution. – Cris Luengo Jan 12 '22 at 05:34
  • In the `if all(value)` case, you overwrite `vals` with its first field, which means that in subsequent iterations of the loop `vals` is now something different. I suggest you use a different variable name there. You also have to think how to combine the results of calling `extractValues` on each field. – Cris Luengo Jan 12 '22 at 05:40
  • @Chris Luengo , I saw the problem with vals, and renamed it, still not the expected behaviour. Thank you! – Cassius Jan 12 '22 at 07:42

1 Answers1

0

As it is known beforehand what fields are requested you can arrange the subsequent filed names in a cell array and use a loop to extract the value:

names = {'values', 'model1', 'values', 'mission', 'values', 'alt'};
out = S;
for name : names
  out = out.(name{1});
end 

So that is a loop version of using:

out = S.values.model1.values.mission.values.alt;

EDIT:

If you want to list all field names and all field values you can used these functions:

function out = names(s, p)
  if isstruct(s)
    out = {};
    f = fieldnames(s);
    for i = 1:numel(f)
      s1 = s.(f{i});
      p1 = [p '.' f{i}];
      out = [out; names(s1, p1)];
    end
  else
    out = {p};
  end
end
  
function out = values(s)  
  if isstruct(s)
    out = {}; 
    f = fieldnames(s);
    for i = 1:numel(f)
      out = [out; values(s.(f{i}))];
    end
  else
    out = {s};
  end
end

Use them as:

n = names(S, 'S');
v = values(S);
rahnema1
  • 15,264
  • 3
  • 15
  • 27