开发者

How can I get counterdiagonals of a matrix and concatenate them?

开发者 https://www.devze.com 2023-01-27 14:05 出处:网络
Short Version How can I do concatMap in MATLAB? I\'m trying to build a single vector from a series of smaller, differently sized vectors. I know I can do:

Short Version

How can I do concatMap in MATLAB? I'm trying to build a single vector from a series of smaller, differently sized vectors. I know I can do:

result = [];
for i=1:N
    result = [result nextPart(i)];
end

but that has a serious speed impact and there must be a smarter way to do conc开发者_如何学运维atMap.


Long Version

I'm trying to write a MATLAB function that returns the counterdiagonals of a block. For example, if you have the block:

1 2 4
3 5 7
6 8 9

then counterDiagonals(block) should return [1 2 3 4 5 6 7 8 9].

I have a function that will find a single counter diagonal of a block. i.e. counterDiagonal(x, 3) will return [4 5 6].

Therefore, counterDiagonals should be as simple as concatMap counterDiagonal(x, i) (1:N) where N is (2*length(block)-1). How can I do this in MATLAB in an efficient way?


One problem with the accepted answer: if the matrix A had zeros, they will be incorrectly removed from the result.. Instead you should work on the indices of the elements:

A = [0 2 4; 3 5 7; 6 8 9];               %# Sample matrix (contains zeros)

ind = reshape(1:numel(A), size(A));      %# indices of elements
ind = fliplr( spdiags( fliplr(ind) ) );  %# get the anti-diagonals (or use ROT90)
ind(ind==0) = [];                        %# keep non-zero indices
result = A(ind);                         %# get elements in desired order

This is very similar to this answer I gave in a previous question (the difference was that the anti-digaonals were in reverse order).


I believe what you want to do can be accomplished using the functions ROT90 and SPDIAGS:

A = [1 2 4; 3 5 7; 6 8 9];  %# Sample matrix
result = rot90(A);          %# Rotate the matrix counter-clockwise
result = spdiags(result);   %# Find all the diagonals
result = result(result ~= 0).';  %'# Remove zero padding and format the results
                                  %#   into a row vector

And you should end up with result = [1 2 3 4 5 6 7 8 9].

EDIT: As Amro mentions in a comment, the above code assumes that there are no zeroes in the original matrix A. If there are zeroes in the original matrix, one solution is to replace them with a non-zero flag value that you know doesn't appear in the original matrix (like, for example, NaN), run the above code, then replace the flag values in the result:

A = [0 2 4; 3 0 7; 6 8 0];  %# Sample matrix
result = rot90(A);          %# Rotate the matrix counter-clockwise
result(result == 0) = nan;  %# Replace zeroes with NaN
result = spdiags(result);   %# Find all the diagonals
result = result(result ~= 0).';  %'# Remove zero padding and format the results
                                  %#   into a row vector
result(isnan(result)) = 0;  %# Put the original zeroes back


Short version:

If you preassign your result array, everything will be a lot faster.

result = zeros(1,knownLengthOfResultsArray); %# such as "numel(block)"
ct = 1;
for i=1:N
    tmp = nextPart(i);
    nTmp = length(tmp);
    result(ct:ct+nTmp-1) = tmp;
    ct = ct + nTmp;
end

Long version:

However, it may be even more efficient to rewrite your algorithm. See e.g. the answers to this question (use fliplr on your array first), or @gnovice's answer.

0

精彩评论

暂无评论...
验证码 换一张
取 消