while loop matrix problem

hi,
I want to use a while loop on matrices, to define a new matrix by calculating one row each time.
I'm trying to do it without creating another loop that will go over the columns. Is that possible?
for example:
z5 and k5 are known matrices. This loop defines c5.
i=1;
while i<imax
if z5(i,:) < z5(i-1,:)
c5(i,:) = k5(i,:);
elseif z5(i,:) > z5(i-1,:)
c5(i,:) = z5(i,:);
else
c5(i,:) = c5(i-1,:);
end
i=i+1;
end
It's not doing what I want it to do and I'm not sure what exactly its doing.
Would appreciate any help and clarification on this matter.

10 Comments

result = z5(i,:) < z5(i-1,:)
is not the same as
for j=1:size(z5,2)
result(j) = z5(i,j) < z5(i-1,j)
end
Test it and see the difference.
I know, but I dont want to create anothor loop (on the rows) as you did.
Is there a way?
Bob Thompson
Bob Thompson on 26 Jul 2019
Edited: Bob Thompson on 26 Jul 2019
if z5(i,:) < z5(i-1,:)
How is this evaluated for each row?
A = [1 2 3;
4 2 1];
It could be argued that the second row of A is greater than the first, because the sum total of the elements is greater than the first row. It could also be argued that the second row is not greater because each individual element is not greater than the corresponding element in the first row.
An inequality comparison statement is really only useful for comparing one piece of information with another. If you would like to complete all of these comparisons at once, and don't want to use a loop, you can use & to have multiple comparisons for one if statement, but this is very tedious for a large z5 matrix.
if z5(i,1) < z5(i-1,1) & z5(i,2) < z5(i-1,2)
Galgool
Galgool on 26 Jul 2019
Edited: Galgool on 26 Jul 2019
No, I dont want to complete all of these comparisons at once.
What I actually want is for each element in the matrices to apply the conditions.
I mean that for any row - j :
i=1;
while i<imax
if z5(i,j) < z5(i-1,j)
c5(i,j) = k5(i,j);
elseif z5(i,j) > z5(i-1,j)
c5(i,j) = z5(i,j);
else
c5(i,j) = c5(i-1,j);
end
i=i+1;
end
But I want to do this without looping on j, and thought that using ":" will replace the j looping.
Is this possible in any other way than looping?
As you can see from our answers, it's not possible without looping because comparisons must be done elementwise to get the results you expect to get.
actually I've just tested it and you're 100% wrong.
As:
i=2;
while i<imax+1
ab1(i,:) = z5(i,:) < z5(i-1,:);
i=i+1;
end
ab1 gives a matrix identical to:
j=1;
while j<jmax+1
i=2;
while i<imax+1
ab1(i,j) = z5(i,j) < z5(i-1,j);
i=i+1;
end
j=j+1;
end
But for some reason c5 doesnt define properly...
Torsten
Torsten on 26 Jul 2019
Edited: Torsten on 26 Jul 2019
If you test
if z5(i,:) < z5(i-1,:)
the result will be true only if the vector v = z5(i,:) < z5(i-1,:) is a vector of ones at all positions.
So if there is only one case for which z5(i,j) >= z5(i-1,j), all other cases for which z5(i,:) < z5(i-1,:) are ignored, positions for which you intend to set c5(i,:) = k5(i,:), I guess.
Maybe this is what you want to do:
jdx1 = z5(i,:) < z5(i-1,:);
jdx2 = z5(i,:) > z5(i-1,:);
jdx3 = z5(i,:) == z5(i-1,:);
c5(i,jdx1) = k5(i,jdx1);
c5(i,jdx2) = z5(i,jdx2);
c5(i,jdx3) = c5(i-1,jdx3);
Actually you're worng. ab1(i,:) = z5(i,:) < z5(i-1,:); works properly (as you can see in (37,8)):
z5:
z5.JPG
ab1:
ab1.JPG
Torsten
Torsten on 26 Jul 2019
Edited: Torsten on 26 Jul 2019
I'm talking about the "if z5(i,:) < z5(i-1,:) ", not about the "v = z5(i,:) < z5(i-1,:) "
Read my answer carefully.
the cyclist
the cyclist on 26 Jul 2019
Edited: the cyclist on 26 Jul 2019
To reiterate what Torsten is saying ...
To enter an if statement on a vector condition, all elements of that vector have to evaluate to true. MATLAB doesn't discern the if condition element-by-element.
That is the fatal flaw in your algorithm

Sign in to comment.

 Accepted Answer

@galgool, before calling someone wrong please learn the language properly, in particular how if works when given a vector as an expression. From the doc:
An expression is true when its result is nonempty and contains only nonzero elements (logical or real numeric). Otherwise, the expression is false.
So, let's look at
if z5(i,:) < z5(i-1,:)
The expression is
z5(i,:) < z5(i-1,:)
The result of that expression is a logical vector (array of 0s and 1s). As per the rule above, the if is true only if all the elements of the vector are 1. I.e. the only time the expression is true is when z5(i, j) < z5(i-1, j) for all j. In general, you should avoid passing a vector to if because people don't know the rule above. The expression you've written is exactly equivalent to:
if all(z(5(i,;) < z5(i-1,:))
which is clearer.
As others have said, you will also have to loop over the columns.
Note that:
i = 2; %your code would error if you actually started at 1!
while i < constant
%some code that doesn't change i or the constant
i = i+1;
end
is more simply written as a for loop:
for i = 2:constant
%some code that doesn't change i or the constant
end
Note that if you didn't have the dependence on the previous c5 row, when z5(i,j) == z5(i-1, j), the whole thing could written without any loop at all.

4 Comments

Thanks for putting me staright and explaining the details.
instead of using:
if z5(i,j) < z5(i-1,j)
c5(i,j) = k5(i,j);
elseif z5(i,j) > z5(i-1,j)
c5(i,j) = z5(i,j);
else
c5(i,j) = c5(i-1,j);
end
I've now written the whole thing without if:
c5(i,:) = k5(i,:).*(z5(i,:) < z5(i-1,:)) + z5(i,:).*(z5(i,:) > z5(i-1,:)) + c5(i-1,:).*(z5(i,:) == z5(i-1,:));
It works properly
That's fine as long as you write a comment explaining exactly what this line does.
My preference, rather than multiplying by logical vectors to select the actual working part of the expression would be:
c5(i, z5(i, :) < z5(i-1, :)) = k5(i, z5(i, :) < z5(i-1, :));
c5(i, z5(i, :) > z5(i-1, :)) = z5(i, z5(i, :) > z5(i-1, :));
c5(i, z5(i, :) == z5(i-1, :)) = c5(i-1, z5(i, :) == z5(i-1, :));
More lines but a lot easier to understand
Its difficult for me to understand the lines you wrote, as you put the inequality condition within the columns of c5, k5 and z5. doesnt that just give zeros and ones for the columns index?
And another thing - is it possible to get it done without a loop? the only eason I used a loop is because c5(i) is dependent on c5(i-1), z5(i-1) and k5(i-1)...
Maybe, this is clearer this way:
mask = z5(i, :) < z5(i-1, :); c5(i, mask) = k5(i, mask); %set c5 values for which mask is true to matching k5 values
mask = z5(i, :) > z5(i-1, :); c5(i, mask) = z5(i, mask); %set c5 values for which mask is true to matching z5 values
mask = z5(i, :) == z5(i-1, :); c5(i, mask) = c5(i-1, mask); %set c5 values for which mask is true to matching value on previous row
If there was the dependence on the previous row of c5, this could be done trivially without a loop, but unfortunately with that dependence it does need the loop... unless you are guaranteed not to have two consecutive identical value in any z5 column.

Sign in to comment.

More Answers (0)

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Tags

Asked:

on 26 Jul 2019

Commented:

on 29 Jul 2019

Community Treasure Hunt

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

Start Hunting!