Как я могу предварительно выделить массив структур в MATLAB? Я хочу предварительно выделить "a" в этом примере, чтобы он не изменялся несколько раз.
a = []
for i = 1:100
a(i).x = i;
end
Как я могу предварительно выделить массив структур в MATLAB? Я хочу предварительно выделить "a" в этом примере, чтобы он не изменялся несколько раз.
a = []
for i = 1:100
a(i).x = i;
end
Использование repmat
на сегодняшний день является наиболее эффективным способом предварительного выделения структур:
N = 10000;
b = repmat(struct('x',1), N, 1 );
Это в ~ 10 раз быстрее с использованием Matlab 2011a, чем при предварительном распределении с помощью индексации, как в
N = 10000;
b(N).x = 1
Метод индексации лишь незначительно быстрее, чем предварительное выделение.
No preallocation: 0.075524
Preallocate Using indexing: 0.063774
Preallocate with repmat: 0.005234
Код ниже на случай, если вы хотите проверить.
clear;
N = 10000;
%1) GROWING A STRUCT
tic;
for ii=1:N
a(ii).x(1)=1;
end
noPreAll = toc;
%2)PREALLOCATING A STRUCT
tic;
b = repmat( struct( 'x', 1 ), N, 1 );
for ii=1:N
b(ii).x(1)=1;
end;
repmatBased=toc;
%3)Index to preallocate
tic;
c(N).x = 1;
for ii=1:N
c(ii).x(1)=1;
end;
preIndex=toc;
disp(['No preallocation: ' num2str(noPreAll)])
disp(['Preallocate Indexing: ' num2str(preIndex)])
disp(['Preallocate with repmat: ' num2str(repmatBased)])
Результаты в командном окне:
No preallocation: 0.075524
Preallocate Indexing: 0.063774
Preallocate with repmat: 0.0052338
>>
PS Мне было бы интересно узнать, почему это так, если кто-нибудь может это объяснить.
Здесь приятно обсудить это в блоге Loren on the Art of MATLAB.
Если вы правильно поняли, вот способы инициализации структуры, которую вы хотите:
a(100).x = 100;
С помощью этого метода мы можем видеть, что элементы заполняются пустыми массивами.
Существует несколько способов инициализации структуры. Например, вы можете использовать команду struct
:
a(1:100) = struct('x',[]);
который устанавливает все поля x
в пустые.
Вы также можете использовать deal
для создания и заполнения структуры, если вы знаете, какие данные должны туда идти
xx = num2cell(1:100);
[a(1:100).x]=deal(xx{:});
a(99).x
ans =
99
Или вы можете снова использовать struct
(обратите внимание, что если поле структуры должно быть массивом ячеек, ячейка должна быть заключена в фигурные скобки!)
a = struct('x',xx)
То, как это должно быть сделано, и самое простое
a=struct('x',cell(1,N));
Если вы исправите отсутствующий "тик" и добавите этот метод в код тестирования, представленный jerad, предложенный выше метод будет немного медленнее, чем repmat, но намного проще в реализации, вот результат:
No preallocation: 0.10137
Preallocate Indexing: 0.07615
Preallocate with repmat: 0.01458
Preallocate with struct: 0.07588
Причина, по которой repmat выполняется быстрее, заключается в том, что значение для каждого поля 'x' присваивается во время предварительного выделения, а не остается пустым. Если вышеописанный метод предварительного выделения изменяется, поэтому мы начинаем со всех полей x с назначенным значением (один), например так:
a=cell(1,N);
a(:)={1};
d=struct('x',a);
Затем бенчмаркинг значительно улучшился, был очень близок или немного быстрее, чем repmat. Разница настолько мала, что каждый раз, когда я запускаю ее, она меняет, какая из них быстрее. Вот пример вывода:
No preallocation: 0.0962
Preallocate Indexing: 0.0745
Preallocate with repmat: 0.0259
Preallocate with struct: 0.0184
И наоборот, если предварительное распределение repmat изменяется, чтобы установить поле пустым, как это
b = repmat( struct( 'x', {} ), N, 1 );
Все преимущество в скорости потеряно
В соответствии с этим ответом, есть и другой способ:
[a.x] = deal(val);
где val
- это значение, которое вы хотите назначить каждому элементу структуры.
Эффект этой команды отличается от эффекта других, поскольку каждому полю x
каждой структуры a
присваивается значение val
.
Вместо предварительного выделения массива структур может быть проще отменить цикл. Таким образом, массив выделяется в первой итерации, а остальные итерации используются для заполнения структур.
a = []
for i = 100:-1:1
a(i).x = i;
end