How can I use a variable number of structure fields as function arguments?

31 views (last 30 days)
Hello,
I have a structure that conatins a function handle and any number of other variables (in this case 4), like so:
MyStruct = struct('MyFun',@example,'a',1,'b',2,'c',5,'d',37);
where example is a simple function that takes in a variable number of arguments and displays them, like so:
function [] = example(varargin)
for n = 1:2:length(varargin)
disp(['Argument ' varargin{n} ' = ' num2str(varargin{n+1})])
end
I would like to call the function handle (in this case @example) using the variables stored in MyStruct, like so:
>> X = fieldnames(MyStruct)
X =
5×1 cell array
{'MyFun'}
{'a' }
{'b' }
{'c' }
{'d' }
>> MyStruct.MyFun(X{2}, MyStruct.(X{2}), X{3}, MyStruct.(X{3}), X{4}, MyStruct.(X{4}), X{5}, MyStruct.(X{5}))
Argument a = 1
Argument b = 2
Argument c = 5
Argument d = 37
Is there a way to do this for a structure with any number of fields/variables?
[Note: the function handle can point to one of several functions]
For example:
>> MyStruct.MyFun(X{2}, MyStruct.(X{2}), X{3}, MyStruct.(X{3}), . . . , X{999}, MyStruct.(X{999}))
Any help at all would be greatly appreciated!
Thanks!

Accepted Answer

Stephen23
Stephen23 on 21 May 2020
Edited: Stephen23 on 21 May 2020
Use struct2cell and a comma-separated list:
>> X = fieldnames(MyStruct);
>> Y = struct2cell(MyStruct);
>> C = [X(2:end),Y(2:end)].'; % assumes that the function is the first field!
>> MyStruct.MyFun(C{:})
Argument a = 1
Argument b = 2
Argument c = 5
Argument d = 37
A more robust solution would be to not use positional input arguments for the function, but write it to accept the structure itself.
  3 Comments
Steven Lord
Steven Lord on 21 May 2020
I second the "more robust solution" suggestion. Pass the struct into your functions and let the function itself extract the data it needs from the struct while ignoring the rest.
S = struct('x', 1, 'y', 2, 'z', 3);
timesY = @(x, S) x.*S.y; % ignores S.x and S.z
toPowerZ = @(q, S) q.^(S.z); % ignores S.x and S.y
In fact, if you want your function handles to "remember" S exactly as it existed when the function handle was created (rather than using a struct passed in at run-time), you can simplify this a bit more. If you want to change the S to which the function handles below refer you'll need to recreate those handles.
timesY2 = @(x) x.*S.y;
toPowerZ2 = @(q) q.^(S.z);

Sign in to comment.

More Answers (1)

Bill Tubbs
Bill Tubbs on 5 Apr 2023
Edited: Bill Tubbs on 5 Apr 2023
I recently discovered the function namedargs2cell (since r2019b) and use it for this purpose:
>> MyParams = struct('a',1,'b',2,'c',5,'d',37);
>> MyStruct = struct('Fun',@example,'Params',MyParams);
>> params = namedargs2cell(MyStruct.Params);
>> MyStruct.Fun(params{:})

Categories

Find more on Structures in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!