Find size of matrix, without using `size` in MATLA

2019-03-29 09:12发布

问题:

Suppose I want to find the size of a matrix, but can't use any functions such as size, numel, and length. Are there any neat ways to do this? I can think of a few versions using loops, such as the one below, but is it possible to do this without loops?

function sz = find_size(m)
sz = [0, 0]
   for ii = m'    %' or m(1,:) (probably faster)
      sz(1) = sz(1) + 1;
   end

   for ii = m     %' or m(:,1)'
      sz(2) = sz(2) + 1;
   end    
end

And for the record: This is not a homework, it's out of curiosity. Although the solutions to this question would never be useful in this context, it is possible that they provide new knowledge in terms of how certain functions/techniques can be used.

回答1:

Here is a more generic solution

function sz = find_size(m)
sz = [];
m(f(end), f(end));
    function r = f(e)
        r=[];
        sz=[sz e];
    end
end

Which

  1. Works for arrays, cell arrays and arrays of objects
  2. Its time complexity is constant and independent of matrix size
  3. Does not use any MATLAB functions
  4. Is easy to adapt to higher dimensions


回答2:

For non-empty matrices you can use:

sz = [sum(m(:,1)|1) sum(m(1,:)|1)];

But to cover empty matrices we need more function calls

sz = sqrt([sum(sum(m*m'|1)) sum(sum(m'*m|1))]);

or more lines

n=m&0;
n(end+1,end+1)=1;
[I,J]=find(n);
sz=[I,J]-1;

Which both work fine for m=zeros(0,0), m=zeros(0,10) and m=zeros(10,0).



回答3:

Incremental indexing and a try-catch statement works:

function sz = find_size(m)

  sz = [0 0];

  isError = false;
  while ~isError
    try
      b = m(sz(1) + 1, :);
      sz(1) = sz(1) + 1;
    catch
      isError = true;
    end
  end

  isError = false;
  while ~isError
    try
      b = m(:, sz(2) + 1);
      sz(2) = sz(2) + 1;
    catch
      isError = true;
    end
  end

end


回答4:

A quite general solution is:

[ sum(~sum(m(:,[]),2)) sum(~sum(m([],:),1)) ]

It accepts empty matrices (with 0 columns, 0 rows, or both), as well as complex, NaN or inf values.

It is also very fast: for a 1000 × 1000 matrix it takes about 22 microseconds in my old laptop (a for loop with 1e5 repetitions takes 2.2 seconds, measured with tic, toc).


How this works:

The keys to handling empty matrices in a unified way are:

  • empty indexing (that is, indexing with []);
  • the fact that summing along an empty dimension gives zeros.

Let r and c be the (possibly zero) numbers of rows and columns of m. m(:,[]) is an r × 0 empty vector. This holds even if r or c are zero. In addition, this empty indexing automatically provides insensitivity to NaN, inf or complex values in m (and probably accounts for the small computation time as well).

Summing that r × 0 vector along its second dimension (sum(m(:,[]),2)) produces a vector of r × 1 zeros. Negating and summing this vector gives r.

The same procedure is applied for the number of columns, c, by empty-indexing in the first dimension and summing along that dimension.



回答5:

The find command has a neat option to get the last K elements:

I = find(X,K,'last') returns at most the last K indices corresponding to the nonzero entries of the arrayX`.

To get the size, ask for the last k=1 elements. For example,

>> x=zeros(256,4);
>> [numRows,numCols] = find(x|x==0, 1, 'last')
numRows =
   256
numCols =
     4
>> numRows0 = size(x,1), numCols0 = size(x,2)
numRows0 =
   256
numCols0 =
     4

You can use find with the single output argument syntax, which will give you numel:

>> numEl = find(x|x==0, 1, 'last')
numEl =
        1024
>> numEl0 = numel(x)
numEl0 =
        1024

Another straightforward, but less interesting solution uses whos (thanks for the reminder Navan):

s=whos('x'); s.size

Finally, there is format debug.