首页 > 解决方案 > 从下标参考中查找每个维度中的所有索引位置

问题描述

是否有一种优雅的方式可以在重载时从下标引用中检索所有索引位置(对于每个维度)subsref。假设例如 array a = rand(3, 5, 4, 2);,那么下面的下标是等价的:

a()                   <=>    a(:,:,:,:)
a(1, 12)              <=>    a(1, 2, 3, 1)
a(2, :, 5)            <=>    a(2, :, 1, 2)
a(2, 3, end:-5:1)     <=>    a(2, 3, 4, 2), a(2, 3, 3, 1)
a(2, 3, 4, 1, :, 1)   <=>    a(2, 3, 4, 1)   

logic = [false, true, false];
a(logic, 5, 2, 1)     <=>    a(2, 5, 2, 1) 

我感兴趣的是为每个维度找到索引的唯一位置。从上面的例子可以看出:

a()                 =>  idx1 = [1,2,3]; idx2 = [1,2,3,4,5]; idx3 = [1,2,3,4]; idx4 = [1,2];
a(1, 12)            =>  idx1 = [1];     idx2 = [2];         idx3 = [3];       idx4 = [1];
a(2, :, 5)          =>  idx1 = [2];     idx2 = [1,2,3,4,5]; idx3 = [1];       idx4 = [2];
a(2, 3, end:-5:1)   =>  idx1 = [2];     idx2 = [3];         idx3 = [3,4];     idx4 = [1,2];
a(2, 3, 4, 1, :, 1) =>  idx1 = [2];     idx2 = [3];         idx3 = [4];       idx4 = [1];

logic = [false, true, false];
a(logic, 5, 2, 1)   =>  idx1 = [2];     idx2 = [5];         idx3 = [2];       idx4 = [1];

我想这样做的原因有点复杂,但简而言之,我有一个 matlab 类以一种投影模式存储数据,但我仍然希望能够以其他各种投影模式访问数据(主要用于显示目的)。因此,我有依赖属性,可以对存储的数据进行动态转换。

到目前为止,很好,问题是对于从一种投影模式到另一种投影模式的某些数据坐标(累积点)是模棱两可的,除非我知道我在哪个切割(即哪个下标)......能够预先检测一个尺寸在下标之后变为标量 我可以很聪明,并检查是否可以在返回计算值之前对其进行返工...例如,这将避免在一维中绘制数据时出现伪影,因为在一次切割中,您必须选择一个公式并在另一个切另一个。

这是我通过重载subsref方法和解析下标描述结构提出的解决方案:

classdef TestSubscript < handle

    % Lifetime
    methods
        function [this] = TestSubscript()            
            n = 3; m = 5; k = 4; l = 2;
            this.EAz = rand(n,m,k,l);                        
            this.EEl = rand(n,m,k,l);
        end
    end

    % Really stored values in projection mode 1
    properties(Access=private)        
        EAz;
        EEl;
    end

    % Projection in mode 2 computed on the fly
    properties(Dependent)
        EPhi;
    end
    methods

        % Generic formula
        function [ephi] = get.EPhi(this)
            ephi = (sqrt(2)/2)*(this.EAz + this.EEl); % This is dummy (real formula is more complex and depends on coordinates)
        end

        % Detection of special cuts
        function [varargout] = subsref(this, s)

            % First call built-in to apply generic formula
            [varargout{1:nargout}] = builtin('subsref', this, s);            
            if ((length(s) ~= 2) || ~strcmp(s(1).type, '.') || ~strcmp(s(1).subs, 'EPhi') || ~strcmp(s(2).type, '()'))
                return;
            end

            % Then find selected positions on each dimension for this.EPhi(....lalala....) before returning value
            ndim = ndims(this.EAz); 
            selectedPositions = cell(1, ndim);
            subscript = s(2).subs;
            scount = length(subscript);
            if (scount == 0)
                % Call like 'r = this.EPhi();'
                for ki = 1:ndim,
                    selectedPositions{ki} = 1:size(this.EAz, ki); 
                end
            else
                % Call like 'r = this.EPhi(...lalalala....);'
                for ki = 1:ndim,
                    if (ki < scount)
                        % Ok subscript really corresponds to current dimension
                        selectedPositions{ki} = subscript{ki}; 
                        if (ischar(selectedPositions{ki}) && strcmp(selectedPositions{ki}, ':'))
                            selectedPositions{ki} = 1:size(this.EAz, ki);
                        elseif (islogical(selectedPositions{ki}))
                            fullidx = 1:size(this.EAz, ki);
                            selectedPositions{ki} = fullidx(selectedPositions{ki});
                        end
                    else
                        % Subscript is a mix of all remaining dimensions
                        mix = subscript{ki};
                        sizmix = size(this.EAz); sizmix = sizmix(ki:ndim);
                        if (ischar(mix) && strcmp(mix, ':'))
                            mix = 1:prod(sizmix);
                        elseif (islogical(mix))
                            fullidx = 1:prod(sizmix);
                            mix = fullidx(mix);
                        end
                        [selectedPositions{ki:ndim}] = ind2sub(sizmix, mix);                        
                        break;
                    end
                end
            end

            % Make special action if we detect we are on a special cut
            allAzAxisIndexedPositions = unique(selectedPositions{1});
            allElAxisIdxexedPositions = unique(selectedPositions{2});
            if ((length(allAzAxisIndexedPositions) == 1) && (length(allElAxisIdxexedPositions) > 1))
                % We are on vertical cut, TODO: check Az = 0° and force phi = 0° for all encountered accumulation points (Az = 0°, El = 0°)
                disp('Vertical cut detected ... should use formula one');
            elseif ((length(allAzAxisIndexedPositions) > 1) && (length(allElAxisIdxexedPositions) == 1)) 
                % We are on horizontal cut, TODO: check El = 0° and force phi = 90° for all encountered acummulation points (Az = 0°, El = 0°)
                disp('Horizontal cut detected ... should use formula two');
            else
                % Nothing we can do
                disp('Nothing special ... can only use generic formula');
            end

        end

    end

end

然后我可以检测切割(注意:只有前两个轴对公式选择很重要):

a = TestSubscript;

a.EPhi(:, :, 3, 1);
Nothing special ... can only use generic formula

a.EPhi(1, :, 3, 1);
Vertical cut detected ... should use formula one

a.EPhi(:, 2, 3, 1);
Horizontal cut detected ... should use formula two

与“在每个维度上查找选定位置”相关的代码块已经很短了,但也许有更简单的解决方案可以找到所有索引位置?

标签: matlabsubscript

解决方案


推荐阅读