2013-11-27 2 views
3

У меня есть матрица в MATLAB с нулями, и я хотел бы получить другую матрицу с первым N ненулевыми элементами в каждой строке. Скажем, например N = 3, а матрицаНайти первые N ненулевых элементов в каждой строке матрицы

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] 

Я хотел бы результат быть:

B = [2 6 7; 
    3 2 4; 
    1 3 4; 
    1 2 1] 

У меня есть огромная матрица, так что я хотел бы сделать это без петли, может вы, пожалуйста, помогите мне? Большое спасибо!

+2

Вы гарантированно имеете по крайней мере N ненулевых элементов в каждой строке? – Jacob

+0

Да, я знаю. Я гарантированно получаю больше, чем N – Maria

ответ

5

Поскольку магазины MATLAB матрицы в соответствии с column-major order, я сначала транспонированием A, пузырь до не-нулей, и выбрать первые N линии, и транспонирование обратно:

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]; 

транспонирование и заранее выделить выход 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 нули

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 

пузыря вверх не-нули

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 

Выберите первые N строки и транспонировать назад

B(1:N,:)' 

Вы можете сделать бульканье в строке-мажорных порядке, но вы должны были бы получить строку и столбец индексы с помощью find, и выполняйте некоторую сортировку и подбор. Это становится более утомительным и менее читаемым.

+0

Удивительный! Это то, что мне нужно! Большое спасибо! – Maria

+0

+1 для хороших объяснений –

1

Обычно я не хожу с раствором для петли, но это довольно интуитивно:

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 

Поскольку вы гарантированно иметь более N ненулевых за ряд A, которые должны получить работу ,

+0

+1 за то, что обычно не происходит с помощью цикла 'for' :-) –

1
N = 3; 
for ii=1:size(A,1); 
    B(ii,:) = A(ii,find(A(ii,:),N)); 
end 
+0

Я всегда забываю о «первом» использовании. +1 для напоминания. – chappjc

+0

@chappjc в этом случае фактически даже не требуется, по крайней мере, '' first'' является значением по умолчанию – thewaywewalk

+0

Фактически я имел в виду второй аргумент, который по умолчанию является первым, когда вы указываете. Я никогда не использую это. – chappjc

1

Однострочник решение:

B = cell2mat(cellfun(@(c) c(1:N), arrayfun(@(k) nonzeros(A(k,:)), 1:size(A,1), 'uni', false), 'uni', false)).' 

Не очень элегантный и эффективный, но очень весело!

+0

Дополнительные баллы за одну линию, не могут вас там винить. Не совсем быстрее, чем цикл, когда вы указываете. ;) – chappjc

2

Использование accumarray, без петель:

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 
+0

+1 Я знал, что вы придумаете решение 'tankarray' :-) –

0

На самом деле, вы можете сделать это, как код удара:


N=3 
for n=1:size(A,1) 
    [a b]=find(A(n,:)>0,N); 
    B(n,:)=A(n,transpose(b)); 
end 

Тогда я думаю, что это B матрица будет то, что вы хотите.

Смежные вопросы