How to flip non-zero elements of an array and keep zero elements at initial position?

10 visualizzazioni (ultimi 30 giorni)
I have an array (A) with non-zero elements and zero elements.
I want to flip all non-zero elements of A but keep all zero elements at their initial position to get B.
I tried this and it works but I am sure there is a one-liner-ish solution to my problem:
A = [1 2 3 4 5 0];
nz = nnz(A); %nz=5
N = numel(A); %N=6
numZend = N-nz; %numZend = 1
Zend = zeros(numZend); %Zend = 0
A1 = flip(nonzeros(A));%A1 = [5 4 3 2 1]'
B = [A1',Zend]; %B = [5 4 3 2 1 0]
Note that my zero elements are always at the end of my array. I can have 0 to 5 zero elements at the end of my array. Normally, length(A) ranges between 17 and 22.
Thank you :)
  2 Commenti
Image Analyst
Image Analyst il 8 Mar 2022
Give a general example. I have no idea how you can flip non-zero numbers if they are randomly located in a matrix. If you flipped the value right-to-left so that col now goes to (totalColumns-col+1) then it might happen that a non-zero number would like right exactly on top of a zero (which is not allowed to move). Like
m = randi([0, 9], 5, 10)
m = 5×10
0 1 4 9 1 3 8 7 3 1 4 2 8 0 6 2 4 0 6 8 5 4 5 1 3 5 6 1 3 6 1 6 5 0 2 8 7 7 5 2 6 7 6 5 3 7 6 7 5 5
What would be the desired output for that matrix?
A LL
A LL il 8 Mar 2022
Modificato: A LL il 8 Mar 2022
In my case, my zeros are always located at the end of my matrix with something like this:
A=[randi([1,9],5,3);zeros(2,3)]
I tried this, it works but it seems a bit too complicated for what I am trying to do:
A =[randi([1,9],5,3);zeros(2,3)];
nz = nnz(A(:,1));
N = numel(A(:,1));
numZend = N-nz;
Zend = zeros(numZend,numel(A(1,:)));
A1 = flip(A,1);
A2 = A1(numZend+1:end,:);
B = [A2;Zend];
Would you have an idea to make this simpler?

Accedi per commentare.

Risposta accettata

Les Beckham
Les Beckham il 8 Mar 2022
Another possibility (still requires a loop):
A = [ 134 159 122 175 126 0 0
151 170 189 196 0 0 0
155 114 115 126 184 125 0 ]; % test data
B = zeros(size(A));
for i = 1:size(A, 1)
inz = A(i,:)~=0; % logical indices of non-zero elements
B(i,inz) = flip(A(i,inz)) % flip the non-zero elements in this row
end
  1 Commento
Les Beckham
Les Beckham il 8 Mar 2022
Modificato: Les Beckham il 8 Mar 2022
If all rows of the array have the same number of columns of zeros it is possible to do this without the loop.
A = [ 134 159 122 175 126 0 0
151 170 189 196 125 0 0
155 114 115 126 184 0 0 ]; % test data -- modified
B = zeros(size(A));
[r, c] = find(A~=0);
B(A~=0) = fliplr(A(unique(r), unique(c)))
B = 3×7
126 175 122 159 134 0 0 125 196 189 170 151 0 0 184 126 115 114 155 0 0
Not exactly pretty, but it works. I think I like the loop better since it works for different numbers of zeros in each row and is a little easier to follow.

Accedi per commentare.

Più risposte (3)

David Hill
David Hill il 8 Mar 2022
A = [1 2 3 4 5 0];
a=flip(A(A~=0));
a=[a,zeros(1,length(A)-length(a))];
  1 Commento
A LL
A LL il 8 Mar 2022
Modificato: A LL il 8 Mar 2022
Thank you for your answer. :)
Do you have a way to generalize this?
My A is in fact a 20x3 matrix with 2x3 zeros at the end.
Using the nonzeros function (A~=0) returns a full column vector so this will be problematic with A that has dimension greater than 1.

Accedi per commentare.


DGM
DGM il 8 Mar 2022
Modificato: DGM il 8 Mar 2022
I'm sure there's something simpler, but this is what my sleeplessness created:
A = [1:5 0; 11:14 0 0; 21:23 0 0 0; 31 0 32 0 33 0];
A = A.';
mask = A~=0;
B = zeros(size(A));
B(flipud(mask)) = A(mask);
B = flipud(B).'
B = 4×6
5 4 3 2 1 0 14 13 12 11 0 0 23 22 21 0 0 0 33 0 32 0 31 0

Image Analyst
Image Analyst il 8 Mar 2022
Does this do what you want:
% Generate sample data.
A = zeros(6, 10);
for row = 1 : size(A, 1)
numNonZeros = randi([3,7]); % Between 3 and 7 non-zeros to start each row.
A(row, 1:numNonZeros) = randi(9, 1, numNonZeros);
end
A
A = 6×10
5 9 8 3 2 0 0 0 0 0 6 4 8 0 0 0 0 0 0 0 9 2 8 9 6 0 0 0 0 0 9 6 9 2 0 0 0 0 0 0 1 4 8 4 7 3 0 0 0 0 7 3 2 6 0 0 0 0 0 0
% Now we have A, let's flip the non-zeros row-by-row
AFlipped = zeros(size(A));
for row = 1 : size(A, 1)
lastCol = find(A(row,:) ~= 0, 1, 'last');
AFlipped(row, 1:lastCol) = fliplr(A(row, 1:lastCol)); % Do the flip of non-zeros ONLY
end
AFlipped % Show in command window.
AFlipped = 6×10
2 3 8 9 5 0 0 0 0 0 8 4 6 0 0 0 0 0 0 0 6 9 8 2 9 0 0 0 0 0 2 9 6 9 0 0 0 0 0 0 3 7 4 8 4 1 0 0 0 0 6 2 3 7 0 0 0 0 0 0
  1 Commento
A LL
A LL il 8 Mar 2022
Yes, it does! Thank you very much!
It is even more general than what I need since, in my case, I always have a fix number of zero for each row.

Accedi per commentare.

Categorie

Scopri di più su Creating and Concatenating Matrices in Help Center e File Exchange

Prodotti


Release

R2021a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by