Arthur Tarasov
Arthur Tarasov

Reputation: 3791

MATLAB: Using a for loop within another function

I am trying to concatenate several structs. What I take from each struct depends on a function that requires a for loop. Here is my simplified array:

t = 1;
for t = 1:5              %this isn't the for loop I am asking about
    a(t).data = t^2;     %it just creates a simple struct with 5 data entries
end

Here I am doing concatenation manually:

A = [a(1:2).data a(1:3).data a(1:4).data a(1:5).data]     %concatenation function

As you can see, the range (1:2), (1:3), (1:4), and (1:5) can be looped, which I attempt to do like this:

t = 2;
A = [for t = 2:5
         a(1:t).data
     end]

This results in an error "Illegal use of reserved keyword "for"."

How can I do a for loop within the concatenate function? Can I do loops within other functions in Matlab? Is there another way to do it, other than copy/pasting the line and changing 1 number manually?

Upvotes: 1

Views: 310

Answers (2)

MarcinKonowalczyk
MarcinKonowalczyk

Reputation: 2788

As an appendix to gariepy's answer:

The matrix concatenation

A = [A k];

as a way of appending to it is actually pretty slow. You end up reassigning N elements every time you concatenate to an N size vector. If all you're doing is adding elements to the end of it, it is better to use the following syntax

A(end+1) = k;

In MATLAB this is optimized such that on average you only need to reassign about 80% of the elements in a matrix. This might not seam much, but for 10k elements this adds up to ~ an order of magnitude of difference in time (at least for me).

log

Bare in mind that this works only in MATLAB 2012b and higher as described in this thead: Octave/Matlab: Adding new elements to a vector

This is the code I used. tic/toc syntax is not the most accurate method for profiling in MATLAB, but it illustrates the point.

close all; clear all; clc;
t_cnc = []; t_app = [];
N = 1000;
for n = 1:N;
    % Concatenate
    tic;
    A = [];
    for k = 1:n;
        A = [A k];
    end
    t_cnc(end+1) = toc;
    % Append
    tic;
    A = [];
    for k = 1:n;
        A(end+1) = k;
    end
    t_app(end+1) = toc;
end
t_cnc = t_cnc*1000; t_app = t_app*1000; % Convert to ms

% Fit a straight line on a log scale
P1 = polyfit(log(1:N),log(t_cnc),1); P_cnc = @(x) exp(P1(2)).*x.^P1(1);
P2 = polyfit(log(1:N),log(t_app),1); P_app = @(x) exp(P2(2)).*x.^P2(1);

% Plot and save
loglog(1:N,t_cnc,'.',1:N,P_cnc(1:N),'k--',...
       1:N,t_app,'.',1:N,P_app(1:N),'k--');
grid on;
xlabel('log(N)');
ylabel('log(Elapsed time / ms)');
title('Concatenate vs. Append in MATLAB 2014b');
legend('A = [A k]',['O(N^{',num2str(P1(1)),'})'],...
       'A(end+1) = k',['O(N^{',num2str(P2(1)),'})'],...
       'Location','northwest');
saveas(gcf,'Cnc_vs_App_test.png');

Upvotes: 2

gariepy
gariepy

Reputation: 3674

You were close to getting it right! This will do what you want.

A = [];  %% note: no need to initialize t, the for-loop takes care of that
for t = 2:5
   A = [A a(1:t).data] 
end

This seems strange though...you are concatenating the same elements over and over...in this example, you get the result:

A =
     1     4     1     4     9     1     4     9    16     1     4     9    16    25

If what you really need is just the .data elements concatenated into a single array, then that is very simple:

A = [a.data]

A couple of notes about this: why are the brackets necessary? Because the expressions

a.data, a(1:t).data

don't return all the numbers in a single array, like many functions do. They return a separate answer for each element of the structure array. You can test this like so:

>> [b,c,d,e,f] = a.data
b =
     1
c =
     4
d =
     9
e =
    16
f =
    25

Five different answers there. But MATLAB gives you a cheat -- the square brackets! Put an expression like a.data inside square brackets, and all of a sudden those separate answers are compressed into a single array. It's magic!

Another note: for very large arrays, the for-loop version here will be very slow. It would be better to allocate the memory for A ahead of time. In the for-loop here, MATLAB is dynamically resizing the array each time through, and that can be very slow if your for-loop has 1 million iterations. If it's less than 1000 or so, you won't notice it at all.

Finally, the reason that HBHB could not run your struct creating code at the top is that it doesn't work unless a is already defined in your workspace. If you initialize a like this:

%% t = 1;  %% by the way, you don't need this, the t value is overwritten by the loop below
a = [];   %% always initialize!
for t = 1:5              %this isn't the for loop I am asking about
    a(t).data = t^2;     %it just creates a simple struct with 5 data entries
end

then it runs for anyone the first time.

Upvotes: 3

Related Questions