Put values from an array in a while loop into a table

I have a while loop that produces an array of values in each iteration. What I need is for this array to be output in tabular form, ideally into an Excel table, into a new row for each iteration. Here's what the while loop looks like:
while any(maxnrep~=0)
f = [zeros(1,n) 1];
intcon = 1:n;
% A*w + x == s
Aeq = [A 1];
beq = s;
lb = [zeros(1,n) 0];
hb = [maxnrep, Inf];
wx = intlinprog(f, intcon, [], [], Aeq, beq, lb, hb, options);
% number of coins to approximate s
w=round(wx(1:n))';
% the residual x
x = s - sum(w.*A); % == wx(n+1)
if any(w~=y)
iterCount_sub=iterCount-iterCount_sub;
if c~=1
fprintf ('Repeat %.0f times \n', iterCount_sub)
end
fprintf ('\nWay number %.0f\n', c);
fprintf(['%.1f = ' repmat('%.1d*%.0f + ', 1, n) '%.0f\n'], s, [w; A], x)
c=c+1;
iterCount_sub=iterCount;
end
maxnrep = maxnrep - w;
y=w;
iterCount=iterCount+1;
end
The array I need to get into a table is w. I also need separate columns for x and iterCount_sub. As of now, the output looks like this:
Way number 1
12000.0 = 0*6690 + 0*4740 + 0*5990 + 0*6540 + 0*4840 + 0*3240 + 3*4000 + 0
Repeat 609 times
Way number 2
12000.0 = 0*6690 + 1*4740 + 0*5990 + 0*6540 + 0*4840 + 1*3240 + 1*4000 + 20
Repeat 2 times
Way number 3
12000.0 = 0*6690 + 0*4740 + 2*5990 + 0*6540 + 0*4840 + 0*3240 + 0*4000 + 20
Repeat 120 times
etc..
Here, each value that goes before the * sign is part of the w array, and each value that goes after it is part of the A array, the values for which are input by the user.
What I need in the end should look something like this, along with an Excel table:
6690 4740 5990 6540 4840 3240 4000 x rep. count
---- ---- ---- ---- ---- ---- ---- --- ----------
0 0 0 0 0 0 3 0 609
0 1 0 0 0 1 1 20 2
0 0 2 0 0 0 0 20 120
% Is this possible?

 Accepted Answer

There is no need to create lots of separate vectors, doing so would be very inefficient.
Much simpler to convert the matrix using ARRAY2TABLE and then save the table. Note that the table variable/columns names do not need to have 'c' as lead character.
M = [0,0,0,0,0,0,3,0,609;0,1,0,0,0,1,1,20,2;0,0,2,0,0,0,0,20,120]
M = 3×9
0 0 0 0 0 0 3 0 609 0 1 0 0 0 1 1 20 2 0 0 2 0 0 0 0 20 120
S = ["6690","4740","5990","6540","4840","3240","4000","x","rep.count"];
T = array2table(M,'VariableNames',S)
T = 3×9 table
6690 4740 5990 6540 4840 3240 4000 x rep.count ____ ____ ____ ____ ____ ____ ____ __ _________ 0 0 0 0 0 0 3 0 609 0 1 0 0 0 1 1 20 2 0 0 2 0 0 0 0 20 120
writetable(T,"coefficienttable.xlsx")

5 Comments

Ok, I like this a little better, but the same issue as with Simon's approach still stands - I can't predefine the matrix M as its size and values in it depend on the amount of while loop iterations and their results. Is there any way to automate its creation?
As for the S array, would it work if I defined it as
S=[A,"x","rep.count"];
As I've mentioned previously, the array A is defined by the user so I have no way of predicting its size or the values that go into it.
"I can't predefine the matrix M as its size and values in it depend on the amount of while loop iterations and their results. Is there any way to automate its creation?"
The obvious approach is to just append the rows on each iteration:
M = [];
while ..
.. your code
M = [M;w];
end
Or do the same thing with a cell array (might be more efficient):
C = {};
while ..
.. your code
C{end+1} = w;
end
M = vertcat(C{:});
More robust to call STRING explicitly:
S = [string(A),"x","rep.count"];
Thank you so so much for your help! This works exactly as it needs to. One last question, I'm pretty sure I screwed up a little bit with the structure of my code when I was first writing it, but here's what happens when I get the results:
T =
9×9 table
6690 4740 5990 6540 4840 3240 4000 x rep.count
____ ____ ____ ____ ____ ____ ____ ____ _________
0 0 0 0 0 0 3 0 0
0 1 0 0 0 1 1 20 609
0 0 2 0 0 0 0 20 2
1 0 0 0 1 0 0 470 120
1 1 0 0 0 0 0 570 33
1 0 0 0 0 1 0 2070 62
0 0 0 1 0 1 0 2220 33
0 0 0 0 0 3 0 2280 40
0 0 0 0 0 1 0 8760 308
The issue is with the last column rep.count. Initially the value that is displayed there (iterCount_sub) is set to 0, which is why the first value in the column is 0. However, the 2nd value is the one that actually corresponds to the first row, 3rd to 2nd and so on. Is there any way I could suppress that first 0 value and move all of the values up 1 row? The last row doesn't need a rep.count value.
I will repost the while loop code in case it is needed below.
while any(maxnrep~=0)
f = [zeros(1,n) 1];
intcon = 1:n;
% A*w + x == s
Aeq = [A 1];
beq = s;
lb = [zeros(1,n) 0];
hb = [maxnrep, Inf];
wx = intlinprog(f, intcon, [], [], Aeq, beq, lb, hb, options);
% number of coins to approximate s
w=round(wx(1:n))';
% the residual x
x = s - sum(w.*A); % == wx(n+1)
if any(w~=y)
iterCount_sub=iterCount-iterCount_sub;
M = [M;w,x,iterCount_sub];
iterCount_sub=iterCount;
end
maxnrep = maxnrep - w;
y=w;
iterCount=iterCount+1;
end
"Is there any way I could suppress that first 0 value and move all of the values up 1 row?"
You could either modify your code to include that offset, or modify the data after the loop, e.g. something like this:
M(:,end) = [M(2:end,end);NaN];
The last row doesn't need a rep.count value."
But numeric arrays cannot have "holes" in them, so there has to be some value there. What value depends on you. As an alternative you could replace the entire table column/variable with a cell array of scalar numerics and place an empty array in the last cell.
This works perfectly, thank you so much once again!

Sign in to comment.

More Answers (1)

To put info in tables, you best put them in columns. So you could define coefficient vectors for each coefficient, and through your loops add values to these column vectors. In your example, they would look like this
c6690 = [0 0 0]' %a variable name can't start with a number, so I start the name with c(oefficient)
c4740 = [0 1 0]'
c5590 = [0 0 2]'
..
repcount = [609 2 120]'
T = table(c9960, c4740, .., repcount)
Next write it to Excel using writetable (see https://nl.mathworks.com/help/matlab/ref/writetable.html)
writetable(T,"coefficienttable.xlsx")
That should do the trick.

3 Comments

I see, but there is a problem with this approach. The thing is that the array A (the one where the values 6690, 4740 etc. are) is defined by the user and is not always going to be the same size. This means that I would have to somehow automate the creation of those coefficient vectors, so the script creates them according to the input data.
Secondly, the size of those vectors is also dependent on the while loop itself, there is no way I can predict how many iterations it will have to go through beforehand. This means that the length of the vectors would have to be automatically increased with each added value, and I am not quite sure how to do that.
In that case, you could make one matrix instead of column matrices, where the size is dependent on the user input. The user should then also give the column names such that you can define the table as
T = table(M, 'VariableNames', {'c6690','c4740', .., 'repcount'})
Of course, you can also create the variableNames yourself by converting the coefficients to text with num2str() and adding 'c' before it with strcat()
For the length of the vectors/size of the matrix, there are multiple options.
1) You can predefine the length very largely, e.g.
c = zeros(1000,1)
after calculations, you can shorten the matrices to delete the zero elements.
2) You can just add elements in each iteration
c(i) = value
and in the case c is 10 long, and you add c(11), matlab will automatically make c longer to be able to add this element on that location. The drawback here is that this takes a lot of time, so option (1) is recommended.
"...you can define the table as T = table(M, 'VariableNames', {'c6690','c4740', .., 'repcount'})"
No, that will not work. Lets try it with a simple example:
M = rand(5,3);
T = table(M, 'VariableNames', {'c6690','c4740','repcount'})
Error using table
The VariableNames property must contain one name for each variable in the table.
Why does it not work? Because it creates a table with one variable/column, but then attempts to name three variables. Thus the number of variable names does not match the number of variables/columns, as the error clearly states.

Sign in to comment.

Categories

Products

Release

R2022a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!