Miminea
Miminea

Reputation: 13

Matlab - Recursive function to browse and modify a structure

I have some troubles with a Matlab recursive function that I created in order to browse a data structure and modify each field that contains a path starting by a keyword.

My function that replaces a relative path starting by a keyword by an absolute path works perfectly fine and has already been tested (for instance, '$KEYWORD\Desktop\Documents' will be replaced by 'C:\Users\Name\Desktop\Documents')

I am trying to apply this function to a data structure that contains many (too many) fields, with a recursive function. I want this recursive function to browse my data structure, and as soon as it detects a char parameter starting by $KEYWORD, it changes the value by an absolute path stored in an environment parameter. Here is my code:

function newStruct = browse_struct(initStruct)

   fields = fieldnames(initStruct);
   n_fields = length(fields);

   for n = 1 : n_fields
      val = getfield(initStruct, fields{n});
      if isstruct(val)
         browse_struct(val);
      elseif( ischar(val) && val(1)=='$' )
         newVal = replace_keyword(val);
         newStruct = setfield(initStruct, fields{n}, newVal);
      end
   end

end

When I run my code in debug mode, I see that my function browses entirely my data structure, and that the fields of interest are being replaced by what I want, but when the run is over, the new structure is identical to initial one. No field has been changed, so in the end I still have relative paths starting by $KEYWORD, while it should be an absolute path instead.

I also tried to replace the line 7 (the one just under the if condition) by:

newStruct = browse_struct(val)

And it doesn't work either, it completely destroys the initial structure.

I don't know how to fix that problem. Can someone help me please? Thanks a lot.

Upvotes: 1

Views: 950

Answers (1)

Eliahu Aaron
Eliahu Aaron

Reputation: 4552

Problem 1: In your function you are applying changes to newStruct but keep using initStruct for new changes, so you are overriding previous changes to newStruct.

Solution: when you pass a struct (or any object) to a function in MATLAB, you pass it by value, so the original struct does not change. You can simply remove newStruct from the function and only work with initStruct.

Problem 2: browse_struct(val); does not change the struct, and newStruct = browse_struct(val); changes the struct to its field.

Solution: Use newStruct = setfield(initStruct, fields{n}, browse_struct(val));

The corrected function:

function initStruct = browse_struct(initStruct)

    fields = fieldnames(initStruct);
    n_fields = length(fields);

    for n = 1 : n_fields
        val = getfield(initStruct, fields{n});
        if isstruct(val)
            initStruct = setfield(initStruct, fields{n}, browse_struct(val));
        elseif( ischar(val) && val(1)=='$' )
            newVal = replace_keyword(val);
            initStruct = setfield(initStruct, fields{n}, newVal);
        end
    end

end

Instead of using getfield and setfield, MATLAB suggests "Use dynamic field names with structures" so you can modify the function like this:

function initStruct = browse_struct(initStruct)

    fields = fieldnames(initStruct);
    n_fields = length(fields);

    for n = 1 : n_fields
        val = initStruct.(fields{n});
        if isstruct(val)
            initStruct.(fields{n}) = browse_struct(val);
        elseif( ischar(val) && val(1)=='$' )
            newVal = replace_keyword(val);
            initStruct.(fields{n}) = newVal;
        end
    end

end 

Upvotes: 2

Related Questions