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

我的未来我决定 提交于 2019-11-28 04:59:51

问题


Can I shift rows in matrix A with respect to values in vector v?

For instance A and v specified as follows:

A =
    1   0   0
    1   0   0
    1   0   0

v =
    0   1   2

In this case I want to get this matrix from A:

A = 
    1   0   0
    0   1   0
    0   0   1

Every i-th row in A has been shifted by i-th value in v

Can I do this operation with native functions? Or should I write it by myself?

I've tried circshift function, but I couldn't figure out how to shift rows separately.


回答1:


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



回答2:


% 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).




回答3:


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)')



回答4:


Shift vector with circshift in loop, iterating row index.



来源:https://stackoverflow.com/questions/39056658/shift-rows-in-matrix-with-respect-to-vector-values-in-octave-matlab

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