Ở dưới cùng của câu trả lời này là một số mã điểm chuẩn, vì bạn đã làm rõ rằng bạn quan tâm đến hiệu suất thay vì tự ý tránh forcác vòng lặp.
Trong thực tế, tôi nghĩ rằng forcác vòng lặp có lẽ là lựa chọn hiệu quả nhất ở đây. Vì công cụ JIT "mới" (2015b) đã được giới thiệu (các nguồn ) forkhông phải là chậm - thực tế chúng được tối ưu hóa trong nội bộ.
Bạn có thể thấy từ điểm chuẩn rằng mat2celltùy chọn do ThomasIsCoding cung cấp ở đây rất chậm ...

Nếu chúng ta thoát khỏi dòng đó để làm cho tỷ lệ rõ ràng hơn, thì splitapplyphương pháp của tôi khá chậm, tùy chọn tích lũy của obchardon tốt hơn một chút, nhưng các tùy chọn nhanh nhất (và có thể so sánh) đang sử dụng arrayfun(cũng như Thomas đề xuất) hoặc một forvòng lặp. Lưu ý rằng arrayfunvề cơ bản là một forvòng lặp ngụy trang cho hầu hết các trường hợp sử dụng, vì vậy đây không phải là một mối quan hệ đáng ngạc nhiên!

Tôi khuyên bạn nên sử dụng một forvòng lặp để tăng khả năng đọc mã và hiệu suất tốt nhất.
Chỉnh sửa :
Nếu chúng ta giả định rằng lặp là cách tiếp cận nhanh nhất, chúng ta có thể thực hiện một số tối ưu hóa xung quanh findlệnh.
Đặc biệt
Làm cho Mhợp lý. Như sơ đồ dưới đây cho thấy, điều này có thể nhanh hơn đối với tương đối nhỏ M, nhưng chậm hơn với sự đánh đổi của chuyển đổi loại lớn M.
Sử dụng một logic Mđể lập chỉ mục một mảng 1:size(M,2)thay vì sử dụng find. Điều này tránh phần chậm nhất của vòng lặp ( findlệnh) và vượt xa chi phí chuyển đổi loại, làm cho nó trở thành tùy chọn nhanh nhất.
Dưới đây là khuyến nghị của tôi cho hiệu suất tốt nhất:
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
Tôi đã thêm điều này vào điểm chuẩn bên dưới, đây là so sánh các cách tiếp cận kiểu vòng lặp:
Mã điểm chuẩn:
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
forvòng lặp? Đối với vấn đề này, với các phiên bản hiện đại của MATLAB, tôi hoàn toàn nghi ngờ mộtforvòng lặp là giải pháp nhanh nhất. Nếu bạn gặp vấn đề về hiệu suất, tôi nghi ngờ bạn đang tìm sai giải pháp dựa trên lời khuyên đã lỗi thời.