Using Matlab 'find' in a 3D logical array along the 3rd dimension only

假如想象 提交于 2019-12-20 04:08:12

问题


I have a 3D logical array, for example:

A = randi([0 1],x,y,z);

where x,y,z are integers.

Is there a way to find the first true value along the 3rd dimension 'z', for each (x,y)?

I can do it in a loop like this:

B = zeros(x,y);

for ix = 1:x
    for iy = 1:y
        B(ix,iy) = find(A(ix,iy,:),1,'first');
    end
end

Is there an array operation which will allow me to do it without a loop?


回答1:


Not a very straightforward one.

That is because there may not be a true anywhere along the third dimension.

By the way, what you're doing may lead to an extremely hard to find bug. If it is the case that there is no true value somewhere, find will return the empty matrix ([]). And, assigning an empty matrix to something in MATLAB will delete that element from the array you're assigning to.

Meaning:

  1. B(ix,iy) will be deleted
  2. The number of elements in your B will shrink by 1
  3. All subsequent results will be assigned to the wrong positions in B
  4. When you've reached the end of A (and are thus now indexing beyond the boundary of B), MATLAB will automatically grow the array B to fit your assignment.

You'll be none the wiser, but all the results are meaningless garbage.

Luckily, MATLAB throws a warning if you're doing that on arrays with dimension larger than 1, BUT, if you're using the same technique on vectors (e.g., B is a vector), MATLAB will not warn you.

So, at the very least, do a check:

for ix = 1:x
    for iy = 1:y
        if any(A(ix,iy,:))
            B(ix,iy) = find(A(ix,iy,:), 1, 'first'); 
        end
    end
end

Also note that any can take a second argument specifying the dimension to "any" over, meaning

any(A,3)

will return an x×y array of logicals, containing true if there is a true in A along its third dimension, and false otherwise. This may help you prevent having to compute the indices explicitly (oftentimes, they are not really explicitly needed if you change paradigm).

Now, having said all that, you could use

[~, B] = max(A ~= 0, [], 3);

but you'd still have to do checks on all-zeros:

B(~any(A, 3)) = 0;

I'd say, the loop with the check is just so much more intuitive that it'd have my preference. However, the max technique is about 7 times faster, so when properly documented (probably with the loop as part of the comment above it, as well as in an accompanying unit test), then well, why not.



来源:https://stackoverflow.com/questions/40603108/using-matlab-find-in-a-3d-logical-array-along-the-3rd-dimension-only

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!