我在MATLAB中有一个带零的矩阵,我希望得到另一个矩阵,每行中有第一个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 = [2 6 7;
3 2 4;
1 3 4;
1 2 1]
我有一个巨大的矩阵,所以我想在没有循环的情况下这样做,你能帮帮我吗?非常感谢!
答案 0 :(得分: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
索引零
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检索行和列下标,并在那里进行一些排序和拾取。它变得更乏味,更不易读。
答案 1 :(得分: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
答案 2 :(得分:1)
通常我不使用for循环解决方案,但这非常直观:
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
,因此应该完成工作。
答案 3 :(得分:1)
N = 3;
for ii=1:size(A,1);
B(ii,:) = A( ii,find(A(ii,:),N) );
end
答案 4 :(得分:1)
单线解决方案:
B = cell2mat(cellfun(@(c) c(1:N), arrayfun(@(k) nonzeros(A(k,:)), 1:size(A,1), 'uni', false), 'uni', false)).'
不是非常优雅或高效,但非常有趣!
答案 5 :(得分:0)
实际上,你可以像代码打击一样:
N=3
for n=1:size(A,1)
[a b]=find(A(n,:)>0,N);
B(n,:)=A(n,transpose(b));
end
然后我认为这个B矩阵将是你想要的。