2016-07-05 63 views
1

我正在编写一个用面向对象的Matlab(2016a)编写的项目,我正在尝试优化一些代码以改善运行时。使用探查器我已经确定了一种可能的性能改进---我们使用很多功能,它似乎效率特别低,在其实现中并不特别“matlab”。Matlab:提取单元格内的对象具有特定属性值的数组

本质上,我想知道的是,如果有一种有效的方法来索引到一个Cellobject的类对象中,只抽出那些具有我们感兴趣的特定属性值的类型。目前我们使用for循环,我想知道是否有什么我可以做矢量化或可能使用某种逻辑索引。不幸的是,我的搜索似乎没有找到答案,逻辑索引到使用对象的CellArrays似乎并不是很多人想要做的事情...

这是一个最小的工作示例函数I'试图改进。以下是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); 

回答

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 

有可能是一个方法,使之通过预分配输出阵列更快。我现在正在尝试。 编辑 没有工作......但第一部分应该这样做

+0

谢谢。我会试一试,看看它如何与“真正”的类有更多的事情。 – FakeDIY

+0

有趣的是,当cellarray对象很大时,您的方法会更快,但cellarray对象很小时会更慢(尝试使用10个对象的数组,但是执行查找过程的次数更多)。我认为这是因为在少量物体上做mat2cell等的开销不值得。 – FakeDIY

0

我设法找到一个更好的方法(对于我的具体使用情况),它利用的事实,我对匹配的属性枚举类型。也就是说,我仍然想看看是否还有更多的通用解决方案。当对象的数量很大时@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 
相关问题