【问题标题】:Matlab: Extracting Objects within a Cell Array that have a specific property valueMatlab:在单元阵列中提取具有特定属性值的对象
【发布时间】:2016-11-07 03:55:21
【问题描述】:

我正在开发一个用面向对象的 Matlab (2016a) 编写的项目,我目前正在尝试优化一些代码以改善运行时。使用分析器,我发现了一种可能的性能改进——我们大量使用了一个函数,它的实现似乎效率特别低,而且不是特别“matlab”。

本质上,我想知道是否有一种有效的方法可以索引到类对象的 CellArray 以仅提取具有我们感兴趣的特定属性值的对象。目前我们使用 for 循环来执行此操作我想知道我是否可以做一些事情来矢量化它,或者可能使用某种逻辑索引。不幸的是,我的搜索似乎没有找到答案,使用对象对 CellArrays 进行逻辑索引似乎不是很多人想做的事情......

这是我正在尝试改进的功能的最小工作示例。 MWE 的其他代码如下。

我知道通过更改实现的其余部分来完全避免必须这样做来解决此问题可能更明智。但是,如果可能的话,我宁愿避免这样做。

编辑:在我的典型用例中,单元格对象的数量很少(大约 10 或 20 个),但效率低下的方法被调用了很多(数千次)。这么小的数组,很多查找操作。

%% is there a "more matlab" / faster way to do this?
function outputCellArray = ThereMustBeABetterWayToDoThis(cellArrayOfClassObjects,arrayOfTypesToFind)
outputCellArray = {};

for iType = 1:numel(arrayOfTypesToFind)
    thisType = arrayOfTypesToFind(iType); % this line is the real bottleneck according to the profiler
    for iObject = 1:numel(cellArrayOfClassObjects)


        thisClassObj = cellArrayOfClassObjects{iObject};

        if (thisClassObj.specificEnumType == thisType) % this line is also quite slow
            outputCellArray{end+1} = thisClassObj;
        end
    end
end

类定义:

classdef MyClass < handle %% dummy example class

    properties
        specificEnumType;
        x;
        y;
    end

    methods
        function this = MyClass(x,y,specificEnumType)
           this.specificEnumType = specificEnumType;
           this.x = x;
           this.y = y;
        end
    end
end

还有一个:

classdef EnumType < uint32 %%dummy example class
    enumeration
       Type0 (0),
       Type1 (1),
       Type2 (2),
       Type3 (3)
    end

end

调用整个事物的脚本:

% use this script to call the whole thing

%% we have a cell array of class objects: they each have different enumTypes as a property
cellArrayOfClassObjects{1} = MyClass(rand,rand,EnumType.Type0);
cellArrayOfClassObjects{2} = MyClass(rand,rand,EnumType.Type1);
cellArrayOfClassObjects{3} = MyClass(rand,rand,EnumType.Type2);
cellArrayOfClassObjects{4} = MyClass(rand,rand,EnumType.Type3);
cellArrayOfClassObjects{5} = MyClass(rand,rand,EnumType.Type3);
cellArrayOfClassObjects{6} = MyClass(rand,rand,EnumType.Type2);

%% we want to find the ones that have these specific enumTypes
arrayOfTypesToFind = [EnumType.Type0,EnumType.Type2];

%% there must be a better way than this inefficient method
outputArray = ThereMustBeABetterWayToDoThis(cellArrayOfClassObjects,arrayOfTypesToFind);

【问题讨论】:

    标签: performance matlab oop indexing cell-array


    【解决方案1】:

    好吧,那是一个棘手的问题。为了加快速度,我会尽量避免使用 cellarray。在函数中将单元格更改为对象数组,然后将其扫描为向量以加快循环速度,然后再改回单元格

    试试这个

    cellArrayOfClassObjects=cell(10000,1);
    for i=1:10000
        switch randi(4,1,1)
            case 1
                cellArrayOfClassObjects{i} = MyClass(rand,rand,EnumType.Type0);
            case 2
                cellArrayOfClassObjects{i} = MyClass(rand,rand,EnumType.Type1);
            case 3
                cellArrayOfClassObjects{i} = MyClass(rand,rand,EnumType.Type2);
            case 4
                cellArrayOfClassObjects{i} = MyClass(rand,rand,EnumType.Type3);
        end
    end
    
    %% we want to find the ones that have these specific enumTypes
    arrayOfTypesToFind = [EnumType.Type0,EnumType.Type2];
    
    %% there must be a better way than this inefficient method
    tic
    outputArray = ThereMustBeABetterWayToDoThis(cellArrayOfClassObjects,arrayOfTypesToFind);
    toc
    tic
    outputArray2 = ThereIs(cellArrayOfClassObjects,arrayOfTypesToFind);
    toc
    
    
    function outputCellArray = ThereIs(cellArrayOfClassObjects,arrayOfTypesToFind)
    outputCellArray = {};
    X=[cellArrayOfClassObjects{:}];%matrix of the cell 
    
    for iType = 1:numel(arrayOfTypesToFind)
        %for each type check [X.specificEnumType]==arrayOfTypesToFind(iType)
        % then get the objects by X([X.specificEnumType]==arrayOfTypesToFind(iType))
        % then put them in cells mat2cell( X(...) , 1 , sum of those X(...)
        % and add the to the existing outputCellArray=outputCellArray+matcell
        % in one line
        outputCellArray=[outputCellArray mat2cell(X([X.specificEnumType]==arrayOfTypesToFind(iType)),1,sum([X.specificEnumType]==arrayOfTypesToFind(iType)))];
    end
    
    end
    

    可能有一种方法可以通过预分配输出数组来使其更快。我现在正在尝试。 编辑 那没用...但是第一部分应该这样做

    【讨论】:

    • 谢谢。我会试一试,看看它如何与“真正的”类一起工作。
    • 有趣的是,当 cellarray 对象较大时,您的方法会更快,但当 cellarray 对象较小时,您的方法会更慢(尝试使用 10 个对象的数组,但查找过程更多)。我认为这是因为在少量对象上执行 mat2cell 等开销是不值得的。
    【解决方案2】:

    我设法找到了一种更好的方法(对于我的特定用例),它利用了我匹配的属性是枚举类型这一事实。也就是说,我仍然想看看是否有更通用的解决方案。当对象数量很大时,@Finn 的答案同样好。

    这是我的更新版本。有可能进行进一步的改进。

    function outputCellArray = ExploitEnums(cellArrayOfClassObjects,arrayOfTypesToFind)
    
    
    typesCastToInts = uint32(arrayOfTypesToFind);
    
    objectTaskTypesTakenFromArray = cellfun(@(x) uint32(x.specificEnumType), cellArrayOfClassObjects);
    
    typesExistInBothArrays = ismember(objectTaskTypesTakenFromArray, typesCastToInts);
    matchingIndices = find(typesExistInBothArrays);
    
    if (~isempty(matchingIndices))
        outputCellArray = cellArrayOfClassObjects(matchingIndices);
    end
    
    end
    

    【讨论】:

      猜你喜欢
      • 2018-07-22
      • 2018-03-28
      • 1970-01-01
      • 2013-01-28
      • 1970-01-01
      • 2018-08-03
      • 1970-01-01
      • 2023-02-26
      相关资源
      最近更新 更多