I have a matrix in MATLAB with zeroes and I would like to get another matrix with the first N
non-zero elements in each row. Let\'s say for example N = 3<
N = 3;
for ii=1:size(A,1);
B(ii,:) = A( ii,find(A(ii,:),N) );
end
Since MATLAB stores a matrix according to column-major order, I first transpose A
, bubble up the non-zeros, and pick the first N
lines, and transpose back:
N = 3;
A = [ 0 0 2 0 6 7 9;
3 2 4 7 0 0 6;
0 1 0 3 4 8 6;
1 2 0 0 0 1 3];
Transpose and preallocate output B
At = A';
B = zeros(size(At));
At =
0 3 0 1
0 2 1 2
2 4 0 0
0 7 3 0
6 0 4 0
7 0 8 1
9 6 6 3
Index zeros
idx = At == 0;
idx =
1 0 1 0
1 0 0 0
0 0 1 1
1 0 0 1
0 1 0 1
0 1 0 0
0 0 0 0
Bubble up the non-zeros
B(~sort(idx)) = At(~idx);
B =
2 3 1 1
6 2 3 2
7 4 4 1
9 7 8 3
0 6 6 0
0 0 0 0
0 0 0 0
Select first N
rows and transpose back
B(1:N,:)'
You can do the bubbling in row-major order, but you would need to retrieve the row and column subscripts with find, and do some sorting and picking there. It becomes more tedious and less readable.
One-liner solution:
B = cell2mat(cellfun(@(c) c(1:N), arrayfun(@(k) nonzeros(A(k,:)), 1:size(A,1), 'uni', false), 'uni', false)).'
Not terribly elegant or efficient, but so much fun!
Actually , you can do it like the code blow:
N=3
for n=1:size(A,1)
[a b]=find(A(n,:)>0,N);
B(n,:)=A(n,transpose(b));
end
Then I think this B matrix will be what you want.
Usually I don't go with a for loop solution, but this is fairly intuitive:
N = 3;
[ii,jj] = find(A);
B = zeros(size(A,1),N);
for iRow = 1:size(A,1),
nzcols = jj(ii==iRow);
B(iRow,:) = A(iRow,nzcols(1:N));
end
Since you are guaranteed to have more than N
nonzeros per row of A
, that should get the job done.
Using accumarray
with no loops:
N = 3;
[ii,jj] = find(A); [ii,inds]=sort(ii); jj = jj(inds);
lininds = ii+size(A,1)*(jj-1);
C = accumarray(ii,lininds,[],@(x) {A(x(1:N)')}); %' cell array output
B = vertcat(C{:})
B =
2 6 7
3 2 4
1 3 4
1 2 1