user2663126
user2663126

Reputation: 101

How to shift zero in the last column of a matrix

I have one matrix like below-

A=[1 1 1 1 1;
   0 1 1 1 2;
   0 0 1 1 3]

But I want to place all the 0 at the end of the row, so A should be like-

A=[1 1 1 1 1;
   1 1 1 2 0;
   1 1 3 0 0] 

How can I do this? Matlab experts please help me.

Upvotes: 2

Views: 1655

Answers (7)

Yuval Atzmon
Yuval Atzmon

Reputation: 5945

I've also asked this question and got a super elegant answer (non of above answers is same) here: Optimize deleting matrix leading zeros in MATLAB

Upvotes: 0

Luis Mendo
Luis Mendo

Reputation: 112689

There you go. Whole matrix, no loops, works even for non-contiguous zeros:

A = [1 1 1 1 1; 0 1 1 1 2; 0 0 1 1 3];

At = A.'; %// It's easier to work with the transpose
[~, rows] = sort(At~=0,'descend'); %// This is the important part.
%// It sends the zeros to the end of each column
cols = repmat(1:size(At,2),size(At,1),1);
ind = sub2ind(size(At),rows(:),cols(:));
sol = repmat(NaN,size(At,1),size(At,2));
sol(:) = At(ind);
sol = sol.'; %'// undo transpose

As usual, for Matlab versions that do not support the ~ symbol on function return, change ~ by a dummy variable, for example:

[nada, rows] = sort(At~=0,'descend'); %// This is the important part.

Upvotes: 4

Buck Thorn
Buck Thorn

Reputation: 5073

@LuisMendo's answer is inspiring in its elegance, but I couldn't get it to work (perhaps a matlab version thing). The following (based on his answer) worked for me:

Aaux = fliplr(reshape([1:numel(A)],size(A)));
Aaux(find(A==0))=0;
[Asort iso]=sort(Aaux.',1,'descend');
iso = iso + repmat([0:size(A,1)-1]*size(A,2),size(A,2),1);
A=A.';
A(iso).'

Upvotes: 1

Oleg
Oleg

Reputation: 10676

A more generic example:

A = [1 3 0 1 1;
     0 1 1 1 2;
     0 0 1 1 3]

% Sort columns directly
[~,srtcol] = sort(A == 0,2);
% Sorted positions 
sz  = size(A);
pos = bsxfun(@plus, (srtcol-1)*sz(1), (1:sz(1))'); % or use sub2ind

The result

B = A(pos)
B =
     1     3     1     1     0
     1     1     1     2     0
     1     1     3     0     0

Upvotes: 4

O. Th. B.
O. Th. B.

Reputation: 1353

Try this (just a fast hack):

for row_k = 1:size(A, 1)
   [A_sorted, A_sortmap] = sort(A(row_k, :) == 0, 'ascend');

   % update row in A:    
   A(row_k, :) = A(row_k, A_sortmap);
end

Now optimized for versions of MATLAB not supporting ~ as garbage lhs-identifier.

Upvotes: 1

Engineero
Engineero

Reputation: 12918

If your zeros are always together, you could use the circshift command. This shifts values in an array by a specified number of places, and wraps values that run off the edge over to the other side. It looks like you would need to do this separately for each row in A, so in your example above you could try:

A(2,:) = circshift(A(2,:), [1 -1]);    % shift the second row one to the left with wrapping
A(3,:) = circshift(A(3,:), [1 -2]);    % shift the third row two to the left with wrapping

In general, if your zeros are always at the front of the row in A, you could try something like:

for ii = 1:size(A,1)                              % iterate over rows in A
    numShift = numel(find(A(ii,:) == 0));         % assuming zeros at the front of the row, this is how many times we have to shift the row.
    A(ii,:) = circshift(A(ii,:), [1 -numShift]);  % shift it
end

Upvotes: 1

NKN
NKN

Reputation: 6424

there are many ways to do this. one fast way can be easily like this:

a = [1 2 3 4 0 5 7 0];

idx=(find(a==0));

idx =

     5     8

b=a;   % save a new copy of the vector
b(idx)=[];    % remove zero elements

b =

     1     2     3     4     5     7

c=[b zeros(size(idx))]

c =

     1     2     3     4     5     7     0     0

You may modify this code as well.

Upvotes: 2

Related Questions