3

Due to legacy function calls I'm sometimes forced to write ugly wrappers like this

function return = someWrapper(someField)

a = someField.a;
b = someField.b;
% and so on, realistically it's more like ten variables that
% could actually be grouped in a struct

save('params.mat', 'a', 'b'); %etc.

% then, on another machine, a function loads params.mat, does the calculations
% and saves the result in result.mat containing the variables c,d,...

load('result.mat', 'c', 'd');
return.c = c;
return.d = d;
% again, it's more than just two return values

So the basic idea is to create variables with the same names as someField's fieldnames, run a function and create a return structure using someFunction's return variable's names as fieldnames.

Is there some way simplify this using some loop e.g. over fieldnames(someField)?


Or should I actually use some different approach? Since some further processing is done with someField and result I'd like to keep using structs, but maybe a second question would be

Can save and load redirect varibale names? I.e. could e.g. the variable a in params.mat be stored using someField.a as value instead of having to assign a = someField.a first?

Tobias Kienzler
  • 25,759
  • 22
  • 127
  • 221

3 Answers3

6

Why not something like this?

if this is s:

s.a=1
s.b=2
s.c=3

Then this command creates a matfile named "arguments" with variables a, b, c:

save arguments.mat -struct s

And this command loads a matfiles variables into a structure

r = load('arguments.mat')
Tobias Kienzler
  • 25,759
  • 22
  • 127
  • 221
Miebster
  • 2,365
  • 4
  • 21
  • 27
  • awesome, just what I was looking for but I drifted into a complicated work-around. Thanks, I'll upvote tomorrow (voting limit again...) – Tobias Kienzler Feb 23 '11 at 15:25
2

How about using ASSIGNIN and dynamic fieldnames to loop over the structure fields and create the appropriate variables in the workspace:

function struct2base(s)

for f = fieldnames(s)'
   assignin('base', f{:}, s.(f{:}))
end
b3.
  • 7,094
  • 2
  • 33
  • 48
  • @b3: using the base workspace as well as globals makes your code vulnerable for side effects. – zellus Feb 23 '11 at 13:18
  • @zellus - There are no globals used here. The OP's requirements were to create variables from structure fieldnames. Without using assignin or eval, I'm not sure how this could be done. – b3. Feb 23 '11 at 13:25
  • @b3: You're right, there were no globals mentioned in your answer, but they are part of the same problem field. I consider variable scoping by using functions or classes as essential for writing maintainable code. – zellus Feb 23 '11 at 13:47
  • +1, I didn't know about `assignin` and considered a similar assigning using `eval` but thought that's my last resort due to runtime. Is `assignin` a bit better? – Tobias Kienzler Feb 23 '11 at 13:50
  • @zellus - I agree with your comment re: variable scoping...when possible. However, how would you accomplish what @TobiasKienzler wants while maintaining this strict scoping rule? – b3. Feb 23 '11 at 13:50
  • ... but from the documentation, does that mean I don't generate local return values but directly modify the calling function/script's variables? (**edit** this interferes with b3's discussion with @zellus) – Tobias Kienzler Feb 23 '11 at 13:52
  • oh, now I get it. I'd make this a separate function in my path and simply call something like `struct2base(someField); [a,b] = someFunction(a,b); base2struct('result', a,b);`, right? **edit** since this would be using dynamic interpretation anyway, could I then also construct the function call as a string and use `eval` without much additional performance issues? – Tobias Kienzler Feb 23 '11 at 14:01
  • @Tobias Kienzler - It really depends on your requirements. I read your question to mean that you needed variables in the calling function's workspace to correspond to the fieldnames. If this is not the case then you could use `deal` as @zellus suggested or simply use [STRUCT2CELL](http://www.mathworks.com/help/techdoc/ref/struct2cell.html) to package all the field values into one cell arrray. – b3. Feb 23 '11 at 14:02
  • @Tobias Kienzler - You don't need to use `someFunction` and I'm not sure what you mean by `base2struct`. To process a structure, S, just execute `struct2base(S)`. You'll end up with new variables in the workspace with the same names as the fields of S. If you want to generalize this to work with calling functions then change the 'base' argument of assignin to 'caller'. I would advise against using `eval` as you suggested. I don't think you gain anything by using it. – b3. Feb 23 '11 at 14:10
  • @Tobias Kienzler - I think I understand your question now. Why not do `[return.c, return.d] = someFunction(someField.a, someField.b)`? – b3. Feb 23 '11 at 14:15
  • With `someFunction` I meant the legacy function for which I do that whole conversion, and `base2struct` would the inversion of your function creating a structure from the workspace variables (actually it might have to be called as `base2struct('result', 'a', 'b')`. The gain of using `eval` would then be that the fieldnames would never have to be mentioned explicitly so the wrapper would be more general (assuming the order of fieldnames is the same as the order of `someFunction`'s arguments) – Tobias Kienzler Feb 23 '11 at 14:17
  • ... oh, good point. I simplified the problem too much since the real call to `someFunction` is without arguments but uses `load('dump.mat')` after I did something like `save('dump.mat', 'a', 'b')` (that's because `someFunction` runs on a different machine, if you're wondering about this function "call"). It's obviously an important fact, so I'll edit that in. Sorry for oversimplification – Tobias Kienzler Feb 23 '11 at 14:20
  • turns out what I _actually_ was looking for is way more simple, see [Major Apus' answer](http://stackoverflow.com/questions/5091284/clever-way-to-assign-multiple-fields-at-once/5092879#5092879). But still thank you for mentioning the `assignin` function that may be useful in another context. – Tobias Kienzler Feb 23 '11 at 15:27
  • thanks again for mentioning `assigning`, I used it to write a [`setParameterDefault`](http://stackoverflow.com/questions/795823/default-arguments-in-matlab/5389428#5389428) function – Tobias Kienzler Mar 22 '11 at 09:56
1

Have a look at the deal() function.

zellus
  • 9,617
  • 5
  • 39
  • 56