简体   繁体   中英

Find the first non-zero column of a matrix (vectorized edition)

I am asking myself what the most "vectorized" solution for finding the values of the first non-zero column of a matrix would look like. If a vectorized solution exists but is very ugly/hackish, I am also asking for the most elegant solution.

Let's say we have a Matrix M , for which we can assume that it contains at least one non-zero value:

 M =
     0     0     1     0     0
     0     0     2     0     0
     0     0     3     0     42
     0     0     4     0     0
     0     0     0     0     0

and I would like to find the values in the first column which is not all zeros; so for this example the desired output would be:

 column = 
    1
    2
    3
    4
    0

My first attempt employed a for loop and is working alright, but it is probably not making full use of the tools available in matlab.

>> for i = 1:size(M,2)
    col = M(:,i);
    if find(col) % empty array evaluates to false
        break;
    end
end
>> col
col =
     1
     2
     3
     4
     0

Another solution I came up with makes use of nested find and cellfun calls, but it's probably still not the best approach to the problem.

>> C = find(cellfun(@isempty, cellfun(@find, num2cell(M,1), 'UniformOutput', 0)) == 0)
C =
     3     5
>> M(:,C(1))
ans =
     1
     2
     3
     4
     0

Here's a way to do it and I would leave it to you for measuring the performance improvements from it (if you are interested of course) -

M(:,find(any(M),1))

I would suggest looking into Logical Operation in MATLAB and logical indexing , as they come in real handy for indexing purposes. These should serve you well.

As you asked for a 'vectorised' solution, this one should run a little faster due to logical indexing:

tic; M(:,sum(M)>0); toc
Elapsed time is 0.000020 seconds.

tic; M(:,find(any(M),1)); toc
Elapsed time is 0.000028 seconds.

(Although this is not the most accurate way to measure execute time)

EDIT:

A more accurate way is to measure with timeit on a bigger matrix:

M=rand(1024); 
f1= @() M(:,sum(M)>0);
f2= @() M(:,find(any(M),1)); 
t1=timeit(f1)
t2=timeit(f2)

t1 =
    0.0070
t2 =
   2.3288e-05

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM