Search code examples
matlabpermutationmatlab-struct

How to generate every possible permutation of a MATLAB structure


I have a MATLAB template structure that I'm using as a basis for a more complex output structure

conditions = {'Listen',':=:'};
items = ["apple" "duck"]; % 2 items

stims = cellstr([ ...
    items, ... % text
    items+".PNG", ... % picture
    items+".wav" ... % sound
    ]);

event = struct( ...
    'Cue', struct('duration',2,'jitter',0.25,'shows',conditions), ...
    'Stimuli', struct('duration','sound','shows',stims), ...
    'Delay', struct('duration',2,'jitter',0.25), ...
    'Go', struct('duration',1,'jitter',0.25,'shows','Speak','skip','Cue==:=:'), ...
    'Response', struct('duration',3,'jitter',0.25,'skip','Cue==:=:'));

events output is a 1×1 struct with the fields:

events = 

  1×1 struct with fields:

         Cue: [1×2 struct]
     Stimuli: [1×6 struct]
       Delay: [1×1 struct]
          Go: [1×1 struct]
    Response: [1×1 struct]

I want to generate from this a 1×12 struct that contains each of the possible combinations of each top level field. Like below:

events = 

  1×12 struct array with fields:

         Cue: [1×1 struct]
     Stimuli: [1×1 struct]
       Delay: [1×1 struct]
          Go: [1×1 struct]
    Response: [1×1 struct]

Edit: I should add that I want the output to dynamically reflect changes in the input. For example:

If the user decides to change event.Delay.duration = [1,2,3] it would generate a struct array three times the original size, with each possible delay duration implemented

If the user decides to remove the Cue field entirely, the output should be a struct array half the original size.


Solution

  • That should do the trick:

    eC = struct2cell( event );
    eN  = fieldnames( event );
    
    nums  = cellfun( @numel, eC );
    subs  = cell( numel(nums), 1);
    event = cell( prod(nums) , 1);
    
    for k = 1 : prod(nums)
        [ subs{:} ] = ind2sub( nums, k );
        event{k} = cell2struct( cellfun(@(X,Y) X(Y), eC, subs, 'UniformOutput', false ), eN', 1 );    
    end
    event = cat( 1, event{:} )';
    

    Key point is the ind2sub function, which is in general helpful when dealing with multi-dimensional problems. Breaking them down to one dimension hast two advantages: 1) Nested loops are not needed. 2) We get independent from the number of dimensions.