2

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.

Gunther Struyf
  • 11,158
  • 2
  • 34
  • 58
user2663126
  • 101
  • 12

7 Answers7

4

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.
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
  • Love the no-looping solution. I was trying to figure out a way to avoid loops, but you beat me to it. Very nice. – Engineero Aug 09 '13 at 16:56
  • I am using Matlab 7.8.0.Here "~" sign not working.showing error message "Error: File: com_all.m Line: 26 Column: 3 Expression or statement is incorrect--possibly unbalanced (, {, or [." – user2663126 Aug 09 '13 at 16:58
  • Somehow it dawned on me that `sort` could do the trick. It critically relies on the fact that "When more than one element has the same value, the order of the elements are preserved in the sorted result" as per the documentation – Luis Mendo Aug 09 '13 at 16:58
  • @user2663126 For 7.8.0, if "~" does not work, replace that line by "[nada, rows]..." – Luis Mendo Aug 09 '13 at 16:59
  • I guess my solution was just too simple :P – Ole Thomsen Buus Aug 09 '13 at 17:17
  • @OleThomsenBuus If "too" means "using loops", then yes :-) – Luis Mendo Aug 09 '13 at 18:50
  • I tried your solution and I get the equivalent of `fliplr(A)` ?? – Buck Thorn Aug 09 '13 at 22:03
  • @TryHard How can that be? Considering the third row for example, my solution gives 1 1 3 0 0 (as it should), whereas `fliplr(A)` gives 3 1 1 0 0 – Luis Mendo Aug 09 '13 at 23:03
  • @LuisMendo I really don't know, but I get a different result from you. In any case I was inspired by your answer and posted my own below. – Buck Thorn Aug 10 '13 at 00:19
4

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
Oleg
  • 10,406
  • 3
  • 29
  • 57
2

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.

NKN
  • 6,482
  • 6
  • 36
  • 55
1

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
Engineero
  • 12,340
  • 5
  • 53
  • 75
  • May be you cannot understand my point.My A=[1 1 1 1 1; 0 1 1 1 2; 0 0 1 1 3] but i want A=[1 1 1 1 1; 1 1 1 2 0; 1 1 3 0 0] .it means all the "o" are in last. – user2663126 Aug 09 '13 at 16:45
  • Did you try what I wrote? That does shift all of the zeros so that they are at the end of their row. The output of those first two lines is `[1 1 1 2 0]` and `[1 1 3 0 0]` respectively. – Engineero Aug 09 '13 at 16:51
  • @user2663126 Sorry, _now_ it is working properly. This works if all you want to do is shift your numbers to the left, although it could be improved if you could avoid the `for` loop. – Engineero Aug 09 '13 at 17:00
1

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.

Ole Thomsen Buus
  • 1,333
  • 1
  • 9
  • 24
  • Too fast a hack apparently - forgot to test properly :-) Try it again, with the new correction. – Ole Thomsen Buus Aug 09 '13 at 16:49
  • I am using Matlab 7.8.0.Here "~" sign not working.showing error message "Error: File: com_all.m Line: 26 Column: 3 Expression or statement is incorrect--possibly unbalanced (, {, or [." – user2663126 Aug 09 '13 at 16:58
  • Well ... then you just replace ~ with a variable that you do not use afterwards. Perhaps use `ans` or `dummy`. Or `A_sorted`. – Ole Thomsen Buus Aug 09 '13 at 17:00
1

@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).'
Buck Thorn
  • 5,024
  • 2
  • 17
  • 27
0

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

Community
  • 1
  • 1
Yuval Atzmon
  • 5,645
  • 3
  • 41
  • 74