Negating every second entree in a matrix column
古いコメントを表示
My goal is pretty simple: I have an arbitrary sized matrix holding only positive real numbers and there will not be anymore than two nonzero elements per column at any time, for example:
b = [1 0 1; 0 1.2 2; 1 3 0];
or
b = [1 2 1 0; 0 1.2 0 0; 0 0 0 3; 1.6 0 4 2.2];
Now what I want is to negate every second nonzero entree of a column. The solution I came up with works, but is probably not the most elegant and/or efficient:
for n=1:numel(b(1,:))
isPositive = 0;
for m=1:numel(b(:,n))
if (isPositive == 1 && b(m,n) ~= 0)
b(m,n) = b(m,n)*-1;
break;
end
if (abs(b(m,n)) == b(m,n) && b(m,n) ~= 0)
isPositive = 1;
end
end
end
I am quite new to MATLAB, so if anybody knows a more elegant solution, perhaps not involving any for loops, please share.
Thanks in advance
2 件のコメント
Jan
2011 年 12 月 13 日
The BREAK wil stop the "for m" loop - is this intented?
Instead of "(abs(b(m,n)) == b(m,n) && b(m,n) ~= 0)" you could write "b(m,n) > 0", but if the matrix b has positive values only at first, the test "abs(b(m,n)) == b(m,n)" is useless.
Why do you check if "b(m,n)~=0" before multiplying with -1? In Matlab "-0" is the same as "0".
Michael Dzjaparidze
2011 年 12 月 13 日
採用された回答
その他の回答 (2 件)
Jan
2011 年 12 月 13 日
This negates every second element per column:
b = [1 2 1 0; 0 1.2 0 0; 0 0 0 3; 1.6 0 4 2.2];
gt0 = (b > 0);
even = mod(cumsum(gt0, 1) - 1, 2);
idx = and(gt0, even);
b(idx) = -b(idx);
[EDITED]: After reading your comment, I understand, that you want to negate one element per column only:
b = [1 2 1 0; 0 1.2 0 0; 0 0 0 3; 1.6 0 4 2.2];
gt0 = (b > 0);
idx = and(gt0, cumsum(gt0, 1) == 2);
b(idx) = -b(idx);
Or with a cleaner loop:
[nx, ny] = size(b);
for iy = 1:ny
isPositive = false;
for ix = 1:nx
if b(ix, iy) > 0
if isPositive
b(ix, iy) = -b(ix, iy);
break;
else
isPositive = true;
end
end
end
end
Daniel Shub
2011 年 12 月 13 日
While there are probably more efficient, and some would argue elegant, solutions, the real goal should be to do what you think makes the most sense. It is generally a bad idea to spend time trying to speed up sections of code until you know it is a bottle neck.
I like Andrei's solution, but it might be more confusing 6 months later to figure out what it is doing. I think loops often allow for easier documentation. I think a loop like yours with lots of useful comments is a very elegant solution.
My answer:
for column = 1:size(b, 2)
row = find(b(:, column), 1, 'last');
b(row, column) = -b(row, column);
end
4 件のコメント
Jan
2011 年 12 月 13 日
The question is not very clear. But as far I understand, Michael wants teh 2nd positive element in each column to be neagted. Then you need:
for column = 1:size(b, 2)
row = find(b(:, column), 2, 'first');
b(row(2), column) = -b(row(2), column);
end
Daniel Shub
2011 年 12 月 13 日
@Jan, but according to the question: "there will not be anymore than two nonzero elements per column at any time." As long as there are always exactly 2 non-zero elements the second non-zero element is the last non-zero element. I assumed that there would always be exactly 2 non-zero elements. If there are not, my answer may not give the correct result. The code you put in the comment crashes if there is only one non-zero element, which might be better.
Jan
2011 年 12 月 13 日
@Daniel: Aaaaarrrgh. "every second" and "not be anymore than 2 nonzero". I still do not get the question completely.
I'm taking a break now and have a cup of coffee. Please fix all problems here. Thanks!
Michael Dzjaparidze
2011 年 12 月 13 日
カテゴリ
ヘルプ センター および File Exchange で Matrix Indexing についてさらに検索
製品
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!