1

Suppose we are running an infinite for loop in MATLAB, and we want to store the iterative values in a vector. How can we declare the vector without knowing the size of it?

z=??
for i=1:inf
    z(i,1)=i;
    if(condition)%%condition is met then break out of the loop
        break;
    end;
end;
Wolfie
  • 27,562
  • 7
  • 28
  • 55
Kivtas
  • 27
  • 1
  • 6
  • Remember everything in Matlab is considered to be a matrix. And there is no initialisation required (sometimes needed but not compulsory). So just use your matrix and keep incrementing indices! – PhoenixBlue Aug 15 '18 at 06:43
  • 2
    @Sardar: I’d say they recommend against it. “Deprecate” means they will remove the feature in the future. They have not anmounced such plans, and in fact they made extending a vector size within a loop more efficient some years ago by disassociating storage size and vector size — nowadays appending one elements doubles the storage size, so that subsequent appending will not require reallocation. – Cris Luengo Aug 15 '18 at 09:20
  • 1
    @Sardar: oh, sorry, you wrote “depreciated”, I mis-read that as “deprecated” — sorry! :) – Cris Luengo Aug 15 '18 at 09:27

5 Answers5

2

Please note first that this is bad practise, and you should preallocate where possible.

That being said, using the end keyword is the best option for extending arrays by a single element:

z = [];
for ii = 1:x
    z(end+1, 1) = ii; % Index to the (end+1)th position, extending the array
end

You can also concatenate results from previous iterations, this tends to be slower since you have the assignment variable on both sides of the equals operator

z = [];
for ii = 1:x
    z = [z; ii];
end

Sadar commented that directly indexing out of bounds (as other answers are suggesting) is depreciated by MathWorks, I'm not sure on a source for this.


If your condition computation is separate from the output computation, you could get the required size first

k = 0;
while ~condition
    condition = true; % evaluate the condition here
    k = k + 1;
end

z = zeros( k, 1 ); % now we can pre-allocate
for ii = 1:k
    z(ii) = ii; % assign values
end
Wolfie
  • 27,562
  • 7
  • 28
  • 55
  • Concatenating as in `z = [z; ii]`, is not slower because it repeats `z`, but because it doesn’t let MATLAB do proper memory management. You end up with an O(n^2) operation, whereas the first method is O(n log n). – Cris Luengo Aug 15 '18 at 09:25
  • Thanks @Chris, I think I was probably being lazy in my explanation. The memory management issues I understood to be because the assignment variable was on the left and the right of the `=` - I didn't meant `z` was duplicated. Think we're on the same page(?) – Wolfie Aug 15 '18 at 10:00
  • 1
    I think that in this case, MATLAB creates a new array and copies `z` and the new data into it. The other form just extends the same array, which can be done at 0 cost most of the time because MATLAB internally doubles array size when it needs to grow. – Cris Luengo Aug 15 '18 at 10:16
1

Depending on your use case you might not know the actual number of iterations and therefore vector elements, but you might know the maximum possible number of iterations. As said before, resizing a vector in each loop iteration could be a real performance bottleneck, you might consider something like this:

maxNumIterations = 12345;
myVector = zeros(maxNumIterations, 1);

for n = 1:maxNumIterations
    myVector(n) = someFunctionReturningTheDesiredValue(n);

    if(condition)
        vecLength = n;
        break;
    end
end

% Resize the vector to the length that has actually been filled
myVector = myVector(1:vecLength);

By the way, I'd give you the advice to NOT getting used to use i as an index in Matlab programs as this will mask the imaginary unit i. I ran into some nasty bugs in complex calculations inside loops by doing so, so I would advise to just take n or any other letter of your choice as your go-to loop index variable name even if you are not dealing with complex values in your functions ;)

PluginPenguin
  • 1,576
  • 11
  • 25
0

You can just declare an empty matrix with

z = []

This will create a 0x0 matrix which will resize when you write data to it. In your case it will grow to a vector ix1.

Keep in mind that this is much slower than initializing your vector beforehand with the zeros(dim,dim) function. So if there is any way to figure out the max value of i you should initialize it withz = zeros(i,1)

cheers, Simon

Simon
  • 79
  • 1
  • 6
0

You can initialize z to be an empty array, it'll expand automatically during looping ...something like:

z = [];
for i = 1:Inf
 z(i) = i;
 if (condition)
    break;
 end
end

However this looks nasty (and throws a warning: Warning: FOR loop index is too large. Truncating to 9223372036854775807), I would do here a while (true) or the condition itself and increment manually.

z = [];
i = 0;
while !condition
 i=i+1;
 z[i]=i;
end

And/or if your example is really what you need at the end, replace the re-creation of the array with something like:

while !condition
 i=i+1;
end
z = 1:i;
0

As mentioned in various times in this thread the resizing of an array is very processing intensive, and could take a lot of time.

If processing time is not an issue:

Then something like @Wolfie mentioned would be good enough. In each iteration the array length will be increased and that is that:

z = [];
for ii = 1:x
    %z = [z; ii];
    z(end+1) = ii % Best way
end

If processing time is an issue:

If the processing time is a large factor, and you want it to run as smooth as possible, then you need to preallocating.If you have a rough idea of the maximum number of iterations that will run then you can use @PluginPenguin's suggestion. But there could still be a change of hitting that preset limit, which will break (or severely slow down) the program.

My suggestion:

If your loop is running infinitely until you stop it, you could do occasional resizing. Essentially extending the size as you go, but only doing it once in a while. For example every 100 loops:

z = zeros(100,1);
for i=1:inf
    z(i,1)=i;

    fprintf("%d,\t%d\n",i,length(z)); % See it working

    if i+1 >= length(z)  %The array as run out of space
        %z = [z; zeros(100,1)];   % Extend this array (note the semi-colon)
        z((length(z)+100),1) = 0; % Seems twice as fast as the commented method
    end

    if(condition)%%condition is met then break out of the loop
        break;
    end;
end

This means that the loop can run forever, the array will increase with it, but only every once in a while. This means that the processing time hit will be minimal.

Edit:

As @Cris kindly mentioned MATLAB already does what I proposed internally. This makes two of my comments completely wrong. So the best will be to follow what @Wolfie and @Cris said with:

z(end+1) = i

Hope this helps!

Hein Wessels
  • 937
  • 5
  • 15
  • 1
    Don’t do `z = [z; ii]`, do `z(end+1) = ii` instead. It will allow MATLAB to do proper memory management, and therefore is much, much faster — O(n log n) instead of O(n^2). – Cris Luengo Aug 15 '18 at 09:23
  • Thanks for the tip! I updated my answer. And also change the way I extend the array with an arbitrary number of elements to `z((length(z)+100),1) = 0`. – Hein Wessels Aug 15 '18 at 09:40
  • This is exactly what MATLAB does internally when you do `z(end+1)=ii`, except it doubles the array size. See https://stackoverflow.com/q/48351041/7328782 for an experiment that demonstrates this. – Cris Luengo Aug 15 '18 at 10:13