1

I have (for example) this struct array in MATLAB

g=struct();
g.var1=[0,1,2];
g.var2=[5,6,7];
g.var3={'a','b','c'};
...

I want to create a cell array that samples (meshgrids) all fields one by one

Wanted a cell array;

M×N cell array

{[0]}    {[5]}    {'a'} 
{[0]}    {[5]}    {'b'} 
{[0]}    {[5]}    {'c'} 
{[1]}    {[5]}    {'a'} 
{[1]}    {[5]}    {'b'} 
{[1]}    {[5]}    {'c'} 
{[2]}    {[5]}    {'a'} 
{[2]}    {[5]}    {'b'} 
{[2]}    {[5]}    {'c'} 
{[0]}    {[6]}    {'a'} 
{[0]}    {[6]}    {'b'} 
{[0]}    {[6]}    {'c'} 
{[1]}    {[6]}    {'a'} 
{[1]}    {[6]}    {'b'} 
{[1]}    {[6]}    {'c'} 
...
...

I want my code to work for all general cases, such as an input struct with only 1 field or many fields.

What is a clever way of coding this?

Wolfie
  • 27,562
  • 7
  • 28
  • 55
user2375049
  • 350
  • 2
  • 15

1 Answers1

0

You can use any of the answers to this question to get all combinations of numeric vectors. I'll define the top answer as the function getIndices and use the output indices to operate on your generic structure g.

The only extra handling you have to have is getting numeric arrays and cell arrays to place nice, I simply added an isnumeric check to convert accordingly.

flds = fieldnames( g ); % get structure fields
% Get indices of fields (1:n for each field) and get combinations
idx = cellfun( @(fld) 1:numel(g.(fld)), flds, 'uni', 0 );
idx = getIndices( idx );
% Create output
out = cell(size(idx,1),numel(flds));
for ii = 1:numel(flds)
    if isnumeric( g.(flds{ii}) )
        out(:,ii) = num2cell( g.(flds{ii})(idx(:,ii)) );
    else
        out(:,ii) = g.(flds{ii})(idx(:,ii));
    end
end

function combs = getIndices( vectors )
    % Source: https://stackoverflow.com/a/21895344/3978545
    n = numel(vectors); %// number of vectors
    combs = cell(1,n); %// pre-define to generate comma-separated list
    [combs{end:-1:1}] = ndgrid(vectors{end:-1:1}); %// the reverse order in these two
    %// comma-separated lists is needed to produce the rows of the result matrix in
    %// lexicographical order 
    combs = cat(n+1, combs{:}); %// concat the n n-dim arrays along dimension n+1
    combs = reshape(combs,[],n); %// reshape to obtain desired matrix
end
Wolfie
  • 27,562
  • 7
  • 28
  • 55