Argyll
Argyll

Reputation: 9875

How to conveniently add multiple fields to a Matlab struct dynamically?

I want to set multiple fields in a struct to a single value. The fields are potentially new. And the field names are potentially dynamically defined. The number of field names is dynamically defined. Is there any good way to do it?

For example, the following works if the number of field names is fixed. But it is tedious and silly. And it does not work if the number of field names is allowed to change.

S=struct;
[S.f1,S.f2,S.f3]=deal(input);

Upvotes: 0

Views: 1539

Answers (3)

G.J
G.J

Reputation: 795

What about this ?

S = struct('f1', 1, 'f2', 2);
old_fields = fieldnames(S);
old_values = struct2cell(S);

new_fields = {'f2'; 'f3'; 'f4'}; % 1 replacement, 2 new fields
n_new_fields = numel(new_fields);
value = 0;

all_fields = [old_fields ; new_fields];
all_values = [old_values ; repmat({value}, n_new_fields, 1)];
S = cell2struct(all_values, all_fields);

I am not sure Matlab won't return an error for having twice the same field (can't test right now). If so, you'll need to use

[all_fields, idx] = unique(all_fields);
all_values = all_values(idx);

before calling cell2struct (just be careful as Matlab has changed the behavior of unique in the most recent releases).

Upvotes: 0

CitizenInsane
CitizenInsane

Reputation: 4875

The most simple thing I can think of for now is:

function [myStruct] = InitStruct(myStruct, initValue)
%[
    % Default arguments for demo purpose
    if (nargin < 2), initValue = 42; end
    if (nargin < 1), myStruct = struct('f1', '', 'f2', '', 'f3', ''); end

    % Obtain all current fields in the structure
    fnames = fieldnames(myStruct); 

    % Dynamically set all fields with initValue
    for fi = 1:length(fnames),
        myStruct.(fnames{fi}) = initValue; 
    end
%]
end

NB: It only works if the structure is scalar ... to encompass all case you can add a loop on structure's length:

function [myStruct] = InitStruct(myStruct, initValue)
%[
    if (nargin < 2), initValue = 42; end
    if (nargin < 1), 
        myStruct = struct('f1', '', 'f2', '', 'f3', '');
        myStruct = repmat(myStruct, [2 6]); % Making structure not scalar
    end

    fnames = fieldnames(myStruct);
    for fi = 1:length(fnames),
        for linearIndex = 1:length(myStruct),
            myStruct(linearIndex).(fnames{fi}) = initValue;
        end
    end
%]
end

Upvotes: 2

TroyHaskin
TroyHaskin

Reputation: 8401

For letter-number pairs (e.g., f1, f2, etc.), I'd suggest using struct-arrays for initialization. You can create them by passing a cell array to the struct function of the values you'd like:

ini = 1;
n   = 5;
s = struct('f',repmat({ini},n,1));

Then s is a struct array with initial values ini. You can access elements like s(1).f .... s(n).f. You can also use the deal function with a struct array literal, which I think it cleaner, like this;

ini = 1;
n   = 5;
s(n).f = [];
[s.f] = deal(ini);

For more generic fieldnames, @CitizenInsane's answer using dynamic field references is the only way I know of as well.

This could change if MATLAB would create comma-separated lists from dynamic fields with cell string arguments, but that is but a dream of mine.

Upvotes: 2

Related Questions