When using sparse matrices, it's easy to find non-zero entries quickly (as these are the only elements stored). However, what's the best way to find the first ZERO entry? Using approaches like find(X==0,1)
or find(~X,1)
tend to be slow as these require the negation of the whole matrix. It doesn't feel like that should be necessary -- is there a better way?
For instance, naively iterating over the array seems to be slightly faster than using find(X==0,1)
:
% Create a sparse array [10% filled]
x = sparse(5000,1);
x(randsample(5000,500)) = 1;
nRuns = 1e5;
% Find the first element, a million times
idx = zeros(nRuns,1);
tic
for n=1:nRuns
idx(n) = find(x==0,1);
end
toc
%%
% Create a sparse array [10% filled]
x = sparse(5000,1);
x(randsample(5000,500)) = 1;
nRuns = 1e5;
% Find the first element, a million times
idx = zeros(nRuns,1);
tic
for n=1:nRuns
for kk = 1:numel(x)
[ii,jj] = ind2sub(size(x), kk);
if x(ii,jj)==0; idx(n) = ii + (jj-1)*n; break; end
end
end
toc
But what is the best way to do this?
When using sparse matrices, it's easy to find non-zero entries quickly (as these are the only elements stored). However, what's the best way to find the first ZERO entry? Using approaches like find(X==0,1)
or find(~X,1)
tend to be slow as these require the negation of the whole matrix. It doesn't feel like that should be necessary -- is there a better way?
For instance, naively iterating over the array seems to be slightly faster than using find(X==0,1)
:
% Create a sparse array [10% filled]
x = sparse(5000,1);
x(randsample(5000,500)) = 1;
nRuns = 1e5;
% Find the first element, a million times
idx = zeros(nRuns,1);
tic
for n=1:nRuns
idx(n) = find(x==0,1);
end
toc
%%
% Create a sparse array [10% filled]
x = sparse(5000,1);
x(randsample(5000,500)) = 1;
nRuns = 1e5;
% Find the first element, a million times
idx = zeros(nRuns,1);
tic
for n=1:nRuns
for kk = 1:numel(x)
[ii,jj] = ind2sub(size(x), kk);
if x(ii,jj)==0; idx(n) = ii + (jj-1)*n; break; end
end
end
toc
But what is the best way to do this?
Share Improve this question asked Feb 17 at 23:26 magnesiummagnesium 4852 silver badges11 bronze badges 8 | Show 3 more comments1 Answer
Reset to default 2For positive arrays min is probably the fastest solution:
x = sparse(5000, 1);
x(randsample(5000, 500)) = 1;
[~, idx] = min(x);
ismember can also be used:
[~, ind] = ismember(0, x);
find(X==0,1)
compares the whole matrix to zero (maybe even producing a full matrix?), then looks for the first non-zero element. In the loop you don’t touch most of the matrix. And it being a sparse matrix, you likely have mostly zero elements (if not, don’t use a sparse matrix), so the loop should terminate really quickly. Note thatidx(n) = ii + (jj-1)*n
is the same asidx(n) = kk
. Andx(ii,jj)==0
is the same asx(kk)==0
. So removing the call toind2sub
should simplify and hopefully speed up your code. – Cris Luengo Commented Feb 18 at 1:37