Search code examples
matlaboperator-overloadingoctave

multi-level/recursive assignment subsasgn example in matlab


I am writing a matlab class and would like to overwrite the subasgn operator to achieve this

obj.('elem1').('subelem1').('subsubelem1')=val;

where the level of depth can vary. This type of multi-level assignment is supported in standard struct (but not in containers.Map or dictionary).

from the below link, I found examples for writing a subsasgn for only 1 subfield level, but it does not support multiple levels as struct does

https://www.mathworks.com/help/matlab/matlab_oop/code-patterns-for-subsref-and-subsasgn-methods.html

I am wondering if anyone can give some pointers on how to achieve this?

thanks

Update: [09/26/2024]

my sample code can be found in https://github.com/fangq/jsonlab/blob/master/jdict.m

specifically, the subsref() function can retrieve multi-level subkeys on both MATLAB and Octave.

however, the subsasgn function can only modify the value for only one level of subfield


Solution

  • This type of multi-level assignment can be implemented by two for loops: The forward loop and the backward loop.
    In the forward step the nested structure is converted into a cell array. The value is modified and in the backward step the elements of the cell array are inserted back into their original positions in the nested structure.
    Note that in the forward step the expression opcell{i}.(onekey) = []; is used to prevent unwanted copy of the elements of the nested structure.

    function obj = subsasgn(obj, idxkey, otherobj)
      oplen = length(idxkey);
      opcell = cell (1, oplen + 1);
      opcell{1} = obj.data;
      obj.data = [];
      
      for i = 1:oplen
        idx = idxkey(i);
        onekey = idx.subs;
        opcell{i+1} = opcell{i}.(onekey);
        opcell{i}.(onekey) = [];
      end
      
      opcell{end}.(onekey) = otherobj;
      
      for i = oplen:-1:1
        idx = idxkey(i);
        onekey = idx.subs;
        opcell{i}.(onekey) = opcell{i+1};
      end
      
      obj.data = opcell{1};
    end