Существует ли лучший способ объявить пустую, введенную матрицу в MATLAB?

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

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

Не объявляя переменные этот путь, любой код, который делает "прибытие (end+1) = myClass ()", должен включать особый случай для пустой матрицы по умолчанию, которая имеет тип дважды.

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

5
задан gnovice 7 April 2010 в 18:33
поделиться

2 ответа

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

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();

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

6
ответ дан 14 December 2019 в 04:34
поделиться

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

r = repmat(MyClass, 0);

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

Это будет работать как со старым, так и с новым стилем классов MCOS. Если вы используете все классы нового стиля, то gnovice's "empty()" звучит как хорошая идея.


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

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

В вашем subsasgn:

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, в которой нужно работать. Подобная работа с subsasgn и системой типов может привести к множеству тонких ошибок, включая segfaults. Делая это таким образом, вы получите более "полное" поведение для ваших объектов, определяемых пользователем. Но это требует работы и хрупкости, и вам, вероятно, лучше придерживаться "repmat(class, 0)" или "empty()".

2
ответ дан 14 December 2019 в 04:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: