Матлаб массив структур: быстрое назначение

есть ли способ" вектор " назначить массив 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 ответов


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


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

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 значениям в edge (:).вес.


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

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

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

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

weights = rand(1, 1000);

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

matrices = rand(3, 3, 1000);

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

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

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

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

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

чтобы сделать это поведение понятным, попробуйте сделать короткий массив с clear edges; edges(1:3) = struct('weight',1.0) и, глядя на каждого из edges(1), edges(2) и edges(3). The 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 внутри каждого элемента структуры. Это включает в себя назначение поля в вашем вопросе – это невозможно векторизовать. Вместо этого вы должны переключить структуру массивов, как предлагает ответ Брайана л.


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

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