Shift rows in matrix with respect to vector values in Octave/MATLAB

做~自己de王妃 提交于 2019-11-29 12:10:34

The function circshift does not work as you want and even if you use a vector for the amount of shift, that is interpreted as the amount of shift for each dimension. While it is possible to loop over the rows of your matrix, that will not be very efficient.

More efficient is if you compute the indexing for each row which is actually quite simple:

## First, prepare all your input
octave> A = randi (9, 4, 6)
A =

   8   3   2   7   4   5
   4   4   7   3   9   1
   1   6   3   9   2   3
   7   4   1   9   5   5

octave> v = [0 2 0 1];
octave> sz = size (A);


## Compute how much shift per row, the column index (this will not work in Matlab)
octave> c_idx = mod ((0:(sz(2) -1)) .- v(:), sz(2)) +1
c_idx =

   1   2   3   4   5   6
   5   6   1   2   3   4
   1   2   3   4   5   6
   6   1   2   3   4   5

## Convert it to linear index    
octave> idx = sub2ind (sz, repmat ((1:sz(1))(:), 1, sz(2)) , c_idx);

## All you need is to index
octave> A = A(idx)
A =

   8   3   2   7   4   5
   9   1   4   4   7   3
   1   6   3   9   2   3
   5   7   4   1   9   5
% A and v as above. These could be function input arguments
A = [1 0 0; 1 0 0; 1 0 0]; 
v = [0 1 2];                                          
assert (all (size (v) == [1, size(A, 1)]), ...
        'v needs to be a horizontal vector with as many elements as rows of A');

% Calculate shifted indices
[r, c] = size (A);
tmp = mod (repmat (0 : c-1, r, 1) - repmat (v.', 1, c), c) + 1;
Out = A(sub2ind ([r, c], repmat ([1 : r].', 1, c), tmp))  

  Out =

       1     0     0
       0     1     0
       0     0     1

If performance is an issue, you can replace repmat with an equivalent bsxfun call which is more efficient (I use repmat here for simplicity to demonstrate the approach).

With focus on performance, here's one approach using bsxfun/broadcasting -

[m,n] = size(A);
idx0 = mod(bsxfun(@plus,n-v(:),1:n)-1,n);
out = A(bsxfun(@plus,(idx0*m),(1:m)'))

Sample run -

A =
     1     7     5     7     7
     4     8     5     7     6
     4     2     6     3     2
v =
     3     1     2
out =
     5     7     7     1     7
     6     4     8     5     7
     3     2     4     2     6

Equivalent Octave version to use automatic broadcasting would look something like this -

[m,n] = size(A);
idx0 = mod( ((n-v(:)) + (1:n)) -1 ,n);
out = A((idx0*m)+(1:m)')

Shift vector with circshift in loop, iterating row index.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!