Reputation: 1511
Summary: I want to call a function that returns multiple structs n
times. How can I append the results to existing fields in my output structs (i.e. create vectors) instead of creating new fields that contain a scalar each iteration?
Example: Consider a function sample_fct( x )
that 1) perfroms some operations on x
and saves the result in a couple of new variables (a
and b
in the sample code) and then 2) calls some sub-functions calculate_one( x )
and calculate_two( x )
with a
and b
as input. It doesn't matter what exactly these functions do. Output of these functions is then collected in struct A
and B
.
function [A, B] = sample_fct( x )
a = 1 * x;
b = 2 * x;
[A.one, A.two] = call_functions( a );
[B.one, B.two] = call_functions( b );
function [one, two] = call_functions( input )
one = calculate_one( input );
two = calculate_two( input );
function one = calculate_one( input )
one = input.^2;
end
function two = calculate_two( input )
two = input.^3;
end
end
end
I then want to call this function n
times with different input parameters in my script
n = 3;
for i = 1:n
[A(i), B(i)] = sample_fct( i );
end
When I do this, A
and B
become 1*n structs, each field again containing the fields one
and two
. So in my example with n = 3
I have 3 instances of scalars one
and two
. The output of my sample code looks like this:
>> A
A =
1x3 struct array with fields:
one
two
>> A.one
ans =
1
ans =
4
ans =
9
What I actually want is A
and B
to be 1*2 structs with 1*n vectors one
and two
, so the desired output should look something like this:
>> A
A =
two: [1 8 27]
one: [1 4 9]
How exactly can I do this without [one, two] being my function's output variable and without calling my function for A and B seperately?
Why I want to do this: I want to run a predictive model with different parameter combinations on a time series and calculate some goodness-of-fit measures and other statistics for 1 minute, 1 hour, 1 day, etc. representations. In my example, x
would be the time series, the loop over n
a loop over different parameter vectors, a
and b
representations with different sampling time and one and two
some statistics that I want to gather in structs A
and B
. I'm pretty sure theres a much more sophisticated way to do this but I just can't wrap my head around it.
I know this is easy to do with vectors/matrices instead of structs, but I would like to be able to call my output with a variable name instead of A.hourly(:,19) or something like that, since I calculate many many statistics and not just two in my actual code.
Upvotes: 2
Views: 693
Reputation: 9864
EDIT: Updated based on the error mentioned in the comments.
You can convert them by
A = struct('one', [A.one], 'two', [A.two]);
In general:
D = [fieldnames(A), cellfun(@(x) [A.(x)], fieldnames(A), 'Uni', false)].';
A = struct(D{:});
OLD ANSWER:
You can convert them by
A.one = [A.one];
A.two = [A.two];
In general
for theField = fieldnames(A)'
F = theField{1};
A.(F) = [A.(F)];
end
Upvotes: 3
Reputation: 9696
One alternative would be to have sample_fct take A and B as additional arguments and do the appending inside sample_fct:
[A,B] = sample_fct(1)
for i=2:n
[A,B] = sample_fct(i, A, B)
end
You would then have to change the two call_functions
calls in sample_fct in case of the 3-arguments-call. This could e.g. look like this:
if nargin == 3
[A.one(end+1), A.two(end+1)] = call_functions( a );
[B.one(end+1), B.two(end+1)] = call_functions( b );
elseif nargin == 1
[A.one, A.two] = call_functions( a );
[B.one, B.two] = call_functions( b );
end
As a general remark: I don't see any reason for using nested functions in this case, so I would recommend to rather implement them as normal subfunctions in the same m-file.
Upvotes: 2