Am Ende dieser Antwort steht ein Benchmarking-Code, da Sie klargestellt haben, dass Sie an Leistung interessiert sind, anstatt forSchleifen willkürlich zu vermeiden .
Tatsächlich denke ich, dass forLoops hier wahrscheinlich die performanteste Option sind. Seit Einführung der "neuen" (2015b) JIT-Engine sind ( Quell- ) forSchleifen nicht von Natur aus langsam - tatsächlich werden sie intern optimiert.
Sie können dem Benchmark mat2cellentnehmen, dass die von ThomasIsCoding hier angebotene Option sehr langsam ist ...

Wenn wir diese Linie splitapplyentfernen , um die Skala klarer zu machen, ist meine Methode ziemlich langsam. Obchardons Accumarray-Option ist etwas besser, aber die schnellsten (und vergleichbaren) Optionen verwenden entweder arrayfun(wie auch von Thomas vorgeschlagen) oder eine forSchleife. Beachten Sie, dass dies für die meisten Anwendungsfälle im arrayfunGrunde genommen eine forverschleierte Schleife ist. Dies ist also keine überraschende Verbindung!

Ich würde empfehlen, eine forSchleife zu verwenden, um die Lesbarkeit des Codes und die beste Leistung zu verbessern.
Bearbeiten :
Wenn wir davon ausgehen, dass das Schleifen der schnellste Ansatz ist, können wir einige Optimierungen am findBefehl vornehmen .
Speziell
Machen Sie Mlogisch. Wie das folgende Diagramm zeigt, kann dies für relativ kleine Personen schneller sein M, jedoch langsamer, wenn die Typkonvertierung für große Geräte abgewogen wird M.
Verwenden Sie eine Logik, Mum ein Array zu indizieren, 1:size(M,2)anstatt es zu verwenden find. Dies vermeidet den langsamsten Teil der Schleife (den findBefehl) und überwiegt den Typkonvertierungsaufwand, was ihn zur schnellsten Option macht.
Hier ist meine Empfehlung für die beste Leistung:
function A = f_forlooplogicalindexing( M )
M = logical(M);
k = 1:size(M,2);
N = size(M,1);
A = cell(N,1);
for r = 1:N
A{r} = k(M(r,:));
end
end
Ich habe dies dem unten stehenden Benchmark hinzugefügt. Hier ist der Vergleich von Loop-Ansätzen:
Benchmarking-Code:
rng(904); % Gives OP example for randi([0,1],3)
p = 2:12;
T = NaN( numel(p), 7 );
for ii = p
N = 2^ii;
M = randi([0,1],N);
fprintf( 'N = 2^%.0f = %.0f\n', log2(N), N );
f1 = @()f_arrayfun( M );
f2 = @()f_mat2cell( M );
f3 = @()f_accumarray( M );
f4 = @()f_splitapply( M );
f5 = @()f_forloop( M );
f6 = @()f_forlooplogical( M );
f7 = @()f_forlooplogicalindexing( M );
T(ii, 1) = timeit( f1 );
T(ii, 2) = timeit( f2 );
T(ii, 3) = timeit( f3 );
T(ii, 4) = timeit( f4 );
T(ii, 5) = timeit( f5 );
T(ii, 6) = timeit( f6 );
T(ii, 7) = timeit( f7 );
end
plot( (2.^p).', T(2:end,:) );
legend( {'arrayfun','mat2cell','accumarray','splitapply','for loop',...
'for loop logical', 'for loop logical + indexing'} );
grid on;
xlabel( 'N, where M = random N*N matrix of 1 or 0' );
ylabel( 'Execution time (s)' );
disp( 'Done' );
function A = f_arrayfun( M )
A = arrayfun(@(r) find(M(r,:)),1:size(M,1),'UniformOutput',false);
end
function A = f_mat2cell( M )
[i,j] = find(M.');
A = mat2cell(i,arrayfun(@(r) sum(j==r),min(j):max(j)));
end
function A = f_accumarray( M )
[val,ind] = ind2sub(size(M),find(M.'));
A = accumarray(ind,val,[],@(x) {x});
end
function A = f_splitapply( M )
[r,c] = find(M);
A = splitapply( @(x) {x}, c, r );
end
function A = f_forloop( M )
N = size(M,1);
A = cell(N,1);
for r = 1:N
A{r} = find(M(r,:));
end
end
function A = f_forlooplogical( M )
M = logical(M);
N = size(M,1);
A = cell(N,1);
for r = 1:N
A{r} = find(M(r,:));
end
end
function A = f_forlooplogicalindexing( M )
M = logical(M);
k = 1:size(M,2);
N = size(M,1);
A = cell(N,1);
for r = 1:N
A{r} = k(M(r,:));
end
end
forSchleifen vermeidet ? Für dieses Problem vermute ich bei modernen Versionen von MATLAB stark, dass eineforSchleife die schnellste Lösung ist. Wenn Sie ein Leistungsproblem haben, suchen Sie vermutlich am falschen Ort nach einer Lösung, die auf veralteten Ratschlägen basiert.