Dynamic slicing of Matlab array

前端 未结 1 1603
庸人自扰
庸人自扰 2020-12-21 16:45

I have an n-dimensional array A and want to slice it dynamically, i.e., given a list of array dimensions, like [2 4], and a list of values, like [6 8], I want



        
1条回答
  •  囚心锁ツ
    2020-12-21 17:24

    You can still use the previous post I linked to (which I originally flagged as a duplicate) to answer your question. This original post only slices in one dimension. I originally flagged it as a duplicate and closed it because all you need to do is replace one line of code in the original post's accepted answer to achieve what you want. However, because it isn't that obvious, I have decided to reopen the question and answer the question for you.

    Referring to the previous post, this is what Andrew Janke (the person with the accepted answer on the linked post) did (very clever I might add):

    function out = slice(A, ix, dim)
    
    subses = repmat({':'}, [1 ndims(A)]);
    subses{dim} = ix;
    out = A(subses{:});
    

    Given a matrix A, an index number ix and the dimension you want to access dim, the above function would equivalently perform:

            out = A(:, :, ..., ix, :, :,...:);
                    ^  ^        ^  ^  
    dimensions -->  1  2       dim dim+1
    

    You would access your desired dimension in dim, and place what value you want to use to slice into that dimension. As such, you'd call it like this:

    out = slice(A, ix, dim);
    

    How the function works is that subses would generate a cell array of ':' strings (that will eventually be converted into ':' operators) that is as long as the total number of dimensions of A. Next, you would access the element at dim, which corresponds to the dimension you want and you would replace this with ix. You would then unroll this cell array so that we would access A in the manner that you see in the above equivalent statement.

    Who would have thought that you can use strings to index into an array!?

    Now, to generalize this, all you have to do is make one small but very crucial change. ix would now be a vector of indices, and dim would be a vector of dimensions you want to access. As such, it would look something like this:

    function out = slice(A, ix, dim)
    
    subses = repmat({':'}, [1 ndims(A)]);
    subses(dim) = num2cell(ix);
    out = A(subses{:});
    

    The only difference we see here is the second line of the code. We have to use num2cell so that you can convert each element into a cell array, and we slice into this cell array to replace the : operators with your desired dimensions. Note that we are using () braces and not {} braces. () braces are used to slice through cell arrays while {} are used to access cell array contents. Because we are going to assign multiple cells to subses, () is needed. We then perform our slicing in A accordingly.

    As such, given your problem and with the above modifications, you would do:

    out = slice(A, [6 8], [2 4]);
    

    Be advised that ix and dim must contain the same number of elements and they must be 1D. Also, ix and dim should be sensible inputs (i.e. not floating point and negative). I don't do this error checking because I'm assuming you know what you're doing and you're smart enough to know how to use this properly.


    Good luck!

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