Fred S
Fred S

Reputation: 1511

MATLAB: Nested functions and structs

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

Answers (2)

Mohsen Nosratinia
Mohsen Nosratinia

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

sebastian
sebastian

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

Related Questions