Есть ли лучший способ объявить пустую типизированную матрицу в MATLAB?

Есть ли способ «объявить» переменную с определенным пользовательским типом в MATLAB? zeros () работает только для встроенных числовых типов. Единственное решение, которое я придумал, включает использование repmat () для нулевого дублирования фиктивного объекта:

arr = repmat(myClass(), [1 0])

Без такого объявления переменных любой код, который выполняет «arr (end + 1) = myClass ()», должен включать особый случай для пустой матрицы по умолчанию, которая имеет тип double.

Я пропустил что-нибудь более разумное?


person Arthur Ward    schedule 07.04.2010    source источник


Ответы (2)


Согласно этой документации, все классы имеют empty метод, который создает пустые массивы этого класса. Например:

arr = myClass.empty(0,0);  %# Creates a 0-by-0 array of class myClass

Это также верно для встроенных типов:

a = uint8.empty(0,1);   %# A 0-by-1 uint8 array
b = single.empty(5,0);  %# A 5-by-0 single array
c = cell.empty(0,0);    %# A 0-by-0 cell array


Примечание о предварительном размещении ...

Вы упомянули, что будете наращивать этот массив в цикле следующим образом:

arr(end+1) = myClass();

Если вы знаете, каков будет окончательный размер массива, обычно более эффективно предварительно выделить весь массив вне цикла, а затем перезаписать или изменить элементы массива в вашем цикле. Я обсуждаю, как это можно сделать для пользовательских классов в ответ на другой вопрос.

person gnovice    schedule 07.04.2010

Вот что я использую. Вы можете использовать более сжатую форму, которая принимает аргумент скалярного размера.

r = repmat(MyClass, 0);

Обратите внимание, что вы не объявляете переменную как имеющую тип; это по-прежнему просто значение, содержащееся в переменной, имеющей тип.

Это будет работать как со старым стилем, так и с новыми классами MCOS. Если вы используете все новые классы стилей, gnovice «empty ()» кажется хорошей идеей.


Если вы чувствуете себя продвинутым, есть еще один вариант, который я включил для полноты картины.

Вы также можете обработать это в subsasgn для ваших объектов, по крайней мере, для старого класса Matlab. Если вы выполняете индексированное присвоение унифицированной переменной с помощью определенного пользователем объекта на RHS («правая сторона»), вызывается подсегмент для этого класса, при этом LHS входит как [] (пустое двойное значение). Если у вас есть специальная форма конструктора, которая позволяет вам создавать пустой объект без вызова repmat для объекта, вы можете поддержать это, чтобы пользователям не приходилось предварительно распределять свои переменные с объектами вашего класса.

В вашем подсистеме:

function obj = subsasgn(obj, S, B)
...
s = S(1);
...
switch s.type
    case '()'
        % Handle dispatch on LHS autovivification
        if isnumeric(obj) && isa(B, mfilename('class'))
            % Must use special ctor to preallocate
            obj = feval(class(B), mxdims(size(B)));
        end

Затем в вашем конструкторе создайте форму вызова бэкдора для создания пустых пространств, благословляя предварительно перепрограммированные структуры.

function MyClass(varargin) %constructor

SuperClasses = { }; % if you inherit, fill this in

if nargin == 1 && isa(varargin{1}, 'mxdims')
   % special backdoor to support preallocation without repmat
   s = repmat(DataStructure, msize(varargin{1})); % built-in repmat called on plain struct
   out = class(s, mfilename, SuperClasses{:});
   return;
end
...

Класс @mxdims - это специальный класс, который вам нужно создать, который содержит вектор размера и служит маркером для вызова этой формы бэкдора. Метод msize () возвращает вектор размера, который он представляет.

Если вы определяете MyClass так, чтобы он поддерживал это, вы можете просто выполнить «s (1) = MyClass» без предварительного выделения s. Однако вы не можете использовать "s (end + 1)"; "end" работает только с заранее выделенными значениями.

Это сложная область для работы в Matlab. Работа с подсистемой типов и подобной системой типов может приводить к множеству мелких ошибок, включая segfaults. Поступая таким образом, вы получите более «полное» поведение для ваших пользовательских объектов. Но это связано с работой и хрупкостью, и вам, вероятно, лучше придерживаться «repmat (class, 0)» или «empty ()».

person Andrew Janke    schedule 07.04.2010