Matlab массив структуры: быстрое присваивание - PullRequest
11 голосов
/ 28 октября 2011

Есть ли способ «вектору» назначить массив struct.

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

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. 

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

Заранее спасибо.

Ответы [ 6 ]

13 голосов
/ 12 августа 2012

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

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.

9 голосов
/ 28 октября 2011

Вы можете попробовать использовать функцию 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,35 с длясделка против ~ 0,05 с для цикла), вероятно, из-за вызова mat2cell.Разница в скорости уменьшается, если вы используете ее более одного раза, но она остается в пользу цикла for.

7 голосов
/ 28 октября 2011

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

edges = struct('weight', num2cell(rand(1000000,1)));
2 голосов
/ 28 октября 2011

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

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

weights = rand(1, 1000);

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

matrices = rand(3, 3, 1000);

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

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

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

[edges.weight] = rand(1, 1000);
1 голос
/ 17 марта 2014

Причина, по которой структуры в вашем примере не инициализируются должным образом, заключается в том, что используемый вами синтаксис обращается только к самому последнему элементу в массиве 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 внутри каждого элемента структуры.Это включает в себя назначение поля в вашем вопросе - это невозможно векторизовать.Вместо этого вы должны переключить структуру массивов, как предполагает ответ Брайана Л.

0 голосов
/ 21 декабря 2015

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

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, и вам не нужны другие большие функции для замедления вашей программы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...