Матричный массив Matlab: быстрое назначение

Есть ли способ "vector" назначить массив структуры.

В настоящее время я могу

edges(1000000) = struct('weight',1.0); //This really does not assign the value, I checked on 2009A.
for i=1:1000000; edges(i).weight=1.0; end; 

Но это медленно, я хочу сделать что-то большее, как

edges(:).weight=[rand(1000000,1)]; //with or without the square brackets. 

Любые идеи/предложения для векторизации этого задания, чтобы он был быстрее.

Спасибо заранее.

Ответ 1

Вы можете попробовать использовать функцию Matlab deal, но я нашел, что для этого нужно немного подправить вход (используя этот вопрос: В Matlab для функции с несколькими входами, как использовать один вход как несколько входов?, возможно, есть что-то более простое.

n=100000;
edges(n)=struct('weight',1.0);
m=mat2cell(rand(n,1),ones(n,1),1);
[edges(:).weight]=deal(m{:});

Также я обнаружил, что это не так быстро, как цикл for на моем компьютере (~ 0.35s для сделки против ~ 0.05s для цикла), предположительно из-за вызова mat2cell. Разница в скорости уменьшается, если вы используете это более одного раза, но она остается в пользу цикла for.

Ответ 2

Это намного быстрее, чем сделка или цикл (по крайней мере, в моей системе):

N=10000;
edge(N) = struct('weight',1.0); % initialize the array
values = rand(1,N);  % set the values as a vector

W = mat2cell(values, 1,ones(1,N)); % convert values to a cell
[edge(:).weight] = W{:};

Используя фигурные скобки справа, дает список разделенных запятыми значений всех значений в W (то есть N выходов) и используя квадратные скобки справа присваивает эти N выходов значениям N в ребро (:). weight.

Ответ 3

Вы можете просто написать:

edges = struct('weight', num2cell(rand(1000000,1)));

Ответ 4

Есть ли что-то, требующее особого использования структуры таким образом?

Рассмотрим замену вашего массива структур просто отдельным массивом для каждого члена структуры.

weights = rand(1, 1000);

Если у вас есть элемент структуры, который является массивом, вы можете сделать дополнительный размер:

matrices = rand(3, 3, 1000);

Если вы просто хотите, чтобы все было аккуратно, вы можете поместить эти массивы в структуру:

edges.weights = weights;
edges.matrices = matrices;

Но если вам нужно сохранить массив структур, я думаю, вы можете сделать

[edges.weight] = rand(1, 1000);

Ответ 5

Причина, по которой структуры вашего примера не инициализируются должным образом, заключается в том, что используемый вами синтаксис обрабатывает только последний элемент в массиве struct. Для несуществующего массива остальные из них неявно заполняются структурами, которые имеют значение по умолчанию [] во всех своих полях.

Чтобы сделать это поведение понятным, попробуйте сделать короткий массив с clear edges; edges(1:3) = struct('weight',1.0) и посмотрев на каждый из edges(1), edges(2) и edges(3). Элемент edges(3) имеет 1.0 в своем весе, как вы хотите; остальные имеют [].

Синтаксис для эффективной инициализации массива структур является одним из них.

% Using repmat and full assignment
edges = repmat(struct('weight', 1.0), [1 1000]);

% Using indexing
% NOTE: Only correct if variable is uninitialized!!!
edges(1:1000) = struct('weight', 1.0);  % QUESTIONABLE

Обратите внимание на 1:1000 вместо 1000 при индексировании в массив неинициализированных ребер.

Проблема с формой edges(1:1000): если edges уже инициализирован, этот синтаксис просто обновит значения выбранных элементов. Если ребра имеют более 1000 элементов, остальные останутся без изменений, и ваш код будет ошибкой. Или, если edges - это другой тип, вы можете получить ошибку или странное поведение в зависимости от существующего типа данных. Чтобы быть в безопасности, вам нужно выполнить clear edges перед инициализацией с использованием синтаксиса индексирования. Поэтому лучше просто выполнить полное назначение с формой repmat.

НО: Независимо от того, как вы его инициализируете, такой массив из таких структур всегда будет работать медленно для больших наборов данных. Вы не можете делать реальные "векторизованные" операции над ним, потому что все примитивные массивы разбиты на отдельные mxArrays внутри каждого элемента структуры. Это включает в себя задание поля в вашем вопросе - это невозможно, чтобы векторизовать это. Вместо этого вы должны переключить структуру массивов, как предлагает Брайан L.

Ответ 6

Вы можете использовать обратную структуру, а затем выполнять все операции без каких-либо ошибок как это

x.E(1)=1;
x.E(2)=3;
x.E(2)=8;
x.E(3)=5;

а затем операция, подобная следующей

x.E

ans =

    3     8     5

или как это

x.E(1:2)=2

x = 

    E: [2 2 5]

или, может быть, это

x.E(1:3)=[2,3,4]*5

x = 

    E: [10 15 20]

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