2011-10-28 79 views
11

有没有什么办法可以给“vector”赋一个struct数组。Matlab数组结构:快速赋值

目前我可以

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. 

任何意见/建议,向量化这个任务,这样它会更快。

在此先感谢。

+2

这篇文章可能会有所帮助:http://stackoverflow.com/questions/4166438/how-do-i-define-a-structure-in-matlab/4169216#4169216 – Amro

回答

8

您可以尝试使用Matlab函数deal,但我发现它需要稍微调整输入(使用此问题:In Matlab, for a multiple input function, how to use a single input as multiple inputs?),也许有一些更简单。

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

而且我发现,这是不是几乎一样快的我的电脑上环路(〜用于处理与〜0.05秒的循环0.35S)大概是因为调用mat2cell的。如果您不止一次使用此速度,速度差异会减小,但它仍然支持for循环。

+0

那真棒,谢谢。 – sumodds

+2

这是我的时代。在Octave上:对于这种方法,17K为100K,1.57为1mil,如果我使用循环,则需要使用循环,比如100K的230s。 MATLAB 2009B(差异机器/ OS):使用上述的5s/49s和使用for循环的.22s/2.2s。 – sumodds

2

有什么要求你特别使用这种结构吗?

考虑用结构中的每个成员的单独数组替换您的结构数组。

weights = rand(1, 1000); 

如果你有一个结构部件,其是一个数组,可以使一个额外的维度:

matrices = rand(3, 3, 1000); 

如果你只想让事情变得整齐,你可以把这些数组到一个结构:

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

但是,如果你需要保持结构的数组,我认为你可以做

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

他们都做同样的事情。但是,我想我需要它是一个数组结构(意味着数组的对象),而不是数组的结构(大数组的单个大结构)。 MATLAB中两者有什么区别,有没有什么区别?意思是分配内存,如果是这样,它的含义是什么? – sumodds

+0

无论如何感谢。 :) – sumodds

+1

不同的是,在Matlab中,结构数组(“结构组织”)是非常低效的,因为每个结构将它的每个字段存储在一个单独的数组中,所以你不能对它们进行向量化操作。像Brian这样的数组结构(“planar-organized”)将把它的每个字段存储在原始数组中,这些数组在内存中是连续的,矢量化(快速)Matlab函数将会工作。这对于Matlab来说是一个更好的结构,而且更具惯用性。 –

7

你可以简单地写:

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

这比交易或循环(至少在我的系统上)要快得多:

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个值。

+0

不错!语言优雅而实用!如果Matlab语法允许将数组扩展为参数序列,比如'{values} {:}',那将会很好。尝试了一个函数来获取单元格值列表,但显然它不喜欢以'deal()'的方式分配'varargout'。 – eacousineau

+0

哎呀,我发现我使用'mat2cell()'而不是'num2cell()'。这是函数:['cellexpand()'](https://gist.github.com/eacousineau/9699289#file-cellexpand-m)。 – eacousineau

+0

你也可以使用匿名句柄:'cellexpand = @(x)x {:}; numexpand = @(x)cellexpand(num2cell(x));'。一个例子:'[a,b] = numexpand([1,2]);'。更具体的例子:'[edge.weight] = numexpand([edge.weight] + 50);' – eacousineau

1

您的示例中的结构未正确初始化的原因是您所使用的语法仅针对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个元素,则其他边缘将保持不变,并且您的代码会变成bug。或者,如果edges是不同的类型,则根据其现有的数据类型可能会出现错误或奇怪的行为。为了安全起见,在使用索引语法进行初始化之前,您需要执行clear edges。所以最好只用repmat表格完成全部任务。

但是:无论如何初始化它,像这样的结构数组在处理较大的数据集时总是会很慢。你不能对它进行真正的“矢量化”操作,因为你的原始数组全部被分解,以便在每个struct元素中分离mxArrays。这包括您的问题中的字段分配 - 无法对此进行矢量化。相反,你应该像Brian L的回答所暗示的那样切换一个数组结构。

0

您可以使用反向结构,然后做所有的操作没有任何错误 这样

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快,你不需要其他大的函数来减慢你的程序。