Select first n nonzero elements in each row of matrix

11 visualizzazioni (ultimi 30 giorni)
Hello
How to select first n nonzero elements from each row?
If I have matrix A, and I want result like B (three nonzero elements from each row):
Rusult also can be cell..
A=[1 3 0 2 5
0 2 0 1 0
2 0 0 0 0
3 1 1 0 0];
B=[1 3 2
2 1 0
2 0 0
3 1 1];

Risposta accettata

Stephen23
Stephen23 il 24 Giu 2020
Modificato: Stephen23 il 24 Giu 2020
Linear indexing does this simply and efficiently. The trick is to work down the columns, which requires transposing:
>> A = [1,3,0,2,5;0,2,0,1,0;2,0,0,0,0;3,1,1,0,0]
A =
1 3 0 2 5
0 2 0 1 0
2 0 0 0 0
3 1 1 0 0
>> N = 3;
>> Z = A.';
>> S = size(Z);
>> [~,R] = sort(Z==0,1);
>> [~,C] = ndgrid(1:N,1:S(2));
>> X = sub2ind(S,R(1:N,:),C);
>> B = Z(X).'
B =
1 3 2
2 1 0
2 0 0
3 1 1
Probably the most efficient approach would be to use a simple loop, e.g. (not particularly optimized):
R = size(A,1);
B = zeros(R,N);
for k = 1:R
tmp = nonzeros(A(k,:));
idx = 1:min(N,numel(tmp));
B(k,idx) = tmp(idx);
end
Some timings (1e3 iterations):
Elapsed time is 5.358 seconds. % madhan ravi's with loop and CELLFUN
Elapsed time is 0.606 seconds. % my answer with SUB2IND
Elapsed time is 0.265 seconds. % my answer with loop and indexing

Più risposte (1)

madhan ravi
madhan ravi il 23 Giu 2020
Modificato: madhan ravi il 23 Giu 2020
ix = cumprod(A ~= 0, 2);
B = A(:, max(ix) ~= 0)
%OR
ix = cumprod(A ~= 0, 2); % remove cumprod(...) if you don't expect n consecutive nonzero elements
n = 3;
idx = find(cumsum(ix,2) == n, 1);
[~, c] = ind2sub(size(A), idx);
B = A(:, 1:c)
% OR
% if you don't want to specify n by yourself
ix = cumprod(A ~= 0, 2); % remove cumprod(...) if you don't expect n consecutive nonzero elements
ix1 = cumsum(ix,2);
idx = find(ix1 == max(max(ix1)), 1); % use max(..., [], 'all') for later versions
[~, c] = ind2sub(size(A), idx);
B = A(:, 1:c)
  3 Commenti
madhan ravi
madhan ravi il 23 Giu 2020
Modificato: madhan ravi il 23 Giu 2020
n = 3; % n non-zero elements
B = cell(size(A,1),1);
for k = 1:size(A,1)
B{k} = nonzeros(A(k,:)).';
end
B = cellfun(@(x) x(1:numel(x) < n+1), B, 'un', 0);
B = cell2mat(cellfun(@(x) [x, zeros(1, n-numel(x))], B, 'un',0))
giometar
giometar il 25 Giu 2020
Modificato: giometar il 25 Giu 2020
Thanks madhan ravi for help. Your solution is also warking but solution from
Stephen Cobeldick is better for me

Accedi per commentare.

Community Treasure Hunt

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

Start Hunting!

Translated by