2011-10-28 80 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快,你不需要其他大的函數來減慢你的程序。