alternating and shifting sections of an array

做~自己de王妃 提交于 2019-12-11 17:06:59

问题


I have a n x m array (could be any size array but it will not be a 1 x m) and I want to rotate / shift each square loop individually no matter the array size.

How can I alternate the rotation / shift each square loop no matter the size of the array.

Please note: I'm not trying to calculate the values in the array but shift the values.

My thought process was to get the values of each "square loop" and place them into one row and do a circshift then place them back into another array.

I ran into problems trying to get the values back into the original n x m array size and I wasn't sure how I could loop through the process for different n x m arrays.

The pink highlighted section, left of the arrows is the starting position of the array and it's "loops" and the green highlighted section, right of the arrows is the type of rotation / shift of the values that I'm trying to create. The array could have more than 3 "loops" this is just an example.

Code below:

I=[1:5;6:10;11:15;16:20;21:25;26:30]

[rw,col] = size(I);

outer_1=[I(1,:),I(2:end-1,end).',I(end,end:-1:1),I(end-1:-1:2,1).'] %get values in one row (so I can shift values)
outer_1_shift=circshift(outer_1,[0 1]) %shift values 
new_array=zeros(rw,col);

Ps: I'm using Octave 4.2.2 Ubuntu 18.04


回答1:


Edit: The circshift function was changed for Octave 5.0, the last edit made it compatible with previous versions

1;

function r = rndtrip (n, m, v)
  rv = @(x) x - 2 * (v - 1);
  r = [v * ones(1,rv(m)-1) v:n-v+1 (n-v+1)*ones(1,rv(m)-2)];
  if (rv(m) > 1)
    r = [r n-v+1:-1:v+1];
  endif
endfunction

function idx = ring (n, m , v)

  if (2*(v-1) > min (n, m))
    r = [];
  else
    r = rndtrip (n, m, v);
    c = circshift (rndtrip (m, n, v)(:), - n + 2 * v - 1).';
    idx = sub2ind ([n m], r, c);
  endif

endfunction

# your I
I = reshape (1:30, 5, 6).';

# positive is clockwise, negative ccw
r = [1 -1 1];

for k = 1:numel(r)

  idx = ring (rows(I), columns(I), k);
  I(idx) = I(circshift(idx(:), r(k)));

endfor

I

gives

I =

    6    1    2    3    4
   11    8    9   14    5
   16    7   18   19   10
   21   12   13   24   15
   26   17   22   23   20
   27   28   29   30   25

run it on tio




回答2:


So, I had the same idea as in Andy's comment. Nevertheless, since I was already preparing some code, here is my suggestion:

% Input.
I = reshape(1:30, 5, 6).'
[m, n] = size(I);

% Determine number of loops.
nLoops = min(ceil([m, n] / 2));

% Iterate loops.
for iLoop = 1:nLoops

  % Determine number of repetitions per row / column.
  row = n - 2 * (iLoop - 1);
  col = m - 2 * (iLoop - 1);

  % Initialize indices.
  idx = [];

  % Add top row indices.
  idx = [idx, [repelem(iLoop, row).']; iLoop:(n-(iLoop-1))];

  % Add right column indices.
  idx = [idx, [[iLoop+1:(m-(iLoop-1))]; repelem(n-(iLoop-1), col-1).']];

  if (iLoop != m-(iLoop-1))

    % Add bottom row indices.
    idx = [idx, [repelem(m-(iLoop-1), row-1).'; (n-(iLoop-1)-1:-1:iLoop)]]

  end

  if (iLoop != n-(iLoop-1))

    % Add left column indices.
    idx = [idx, [[(m-(iLoop-1))-1:-1:iLoop+1]; repelem(iLoop, col-2).']]

  end

  % Convert subscript indices to linear indices.
  idx = sub2ind(size(I), idx(1, :), idx(2, :));

  % Determine direction for circular shift operation.
  if (mod(iLoop, 2) == 1)
    direction = [0 1];
  else
    direction = [0 -1];
  end

  % Replace values in I.
  I(idx) = circshift(I(idx), direction);

end

% Output.
I

Unfortunately, I couldn't think of a smarter way to generate the indices, since you need to maintain the right order and avoid double indices. As you can see, I obtain subscript indices with respect to I, since this can be done quite easy using the matrix dimensions and number of loops. Nevertheless, for the circshift operation and later replacing of the values in I, linear indices are more handy, so that's why the sub2ind operation.

Input and output look like this:

I =
    1    2    3    4    5
    6    7    8    9   10
   11   12   13   14   15
   16   17   18   19   20
   21   22   23   24   25
   26   27   28   29   30

I =
    6    1    2    3    4
   11    8    9   14    5
   16    7   18   19   10
   21   12   13   24   15
   26   17   22   23   20
   27   28   29   30   25

I was right, that the "shift direction" changes with every loop?

Hope that helps!

Caution: I haven't tested for generality, yet. So, please report any errors you might come across.



来源:https://stackoverflow.com/questions/56573666/alternating-and-shifting-sections-of-an-array

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