Declaring a vector in matlab whose size we don't know

1.1k views Asked by At

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;
5

There are 5 answers

3
Wolfie On BEST ANSWER

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
0
PluginPenguin On

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 ;)

3
Hein Wessels On

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!

0
Simon On

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

0
Christian Heigele On

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;