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

后端 未结 1 481
无人及你
无人及你 2021-01-25 19:13

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 a

相关标签:
1条回答
  • 2021-01-25 19:27

    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.

    0 讨论(0)
提交回复
热议问题