2012-10-18 57 views
2

我有一個結構數組,有三個字段 - 數組,數組長度和數字。重新排列長度不等的結構數組到單個1d數組

N = 5; 
data = struct; 
for i=1:N 
    n = ceil(rand * 3); 
    data(i).len = n; 
    data(i).array = rand(1,n); 
    data(i).number = i; 
end 

的數據是這樣的:

data = 
1x5 struct array with fields: 
    len = [ 1 3 3 1 1 ] 
    array = [[0.8]; [0.7 0.9 0.4]; [0.7 0 0.3]; [0.1]; [0.3]] 
    number = [ 1 2 3 4 5 ] 

我可以通過多種方式返回數組作爲一個1X9陣列:

>>> [data.array] 
>>> cat(2,data.array) 
[0.8 | 0.7 0.9 0.4 | 0.7 0 0.3 | 0.1 | 0.3]  % | shows array separation 

我想重複一下電話號碼(data.numberlen次,以產生與連接數組相同長度的數組。

我目前做這與arrayfun然後cell2mat

>> x = arrayfun(@(x) repmat(x.number, 1, x.len), data, 'UniformOutput', false) 
x = 
    [1] [1x3 double] [1x3 double] [4] [5] 
>> cell2mat(x) 
[ 1 2 2 2 3 3 3 4 5] 

這使得數字線向上與陣列。

arrays = [ 0.8 | 0.7 0.9 0.4 | 0.7 0 0.3 | 0.1 | 0.3 ] 
numbers = [ 1 | 2 2 2 | 3 3 3 | 4 | 5 ] 

這背後的思想是將數據提供給GPU進行處理 - 但重新排列的數據可以量級比實際處理時間。

Arrayfun當N = 100,000時需要約5秒,並且for循環呼叫repmat需要約4秒。

有更快的方法來重新排列結構中不均勻數組的數據爲匹配長度的1d數組嗎?我願意使用不同的數據結構。


測試矢量化方法:

data = struct; 
data(1).len = 1; 
data(1).array = [1 2 3]; 
data(1).number = 11; 
data(2).len = 0; 
data(2).array = []; 
data(2).number = 12; 
data(3).len = 2; 
data(3).array = [4 5 6; 7 8 9]; 
data(3).number = 13; 

list_of_array = cat(1,data.array) 

idx = zeros(1,size(list_of_array,1)); 
% Set start of each array to 1 
len = cumsum([data.len]) 
idx(len) = 1 
% Flat indices 
idx = cumsum([1 idx(1:end-1)]) 

nf = [data.number] 
repeated_num_faces = nf(idx) 

給人的輸出:

list_of_array = 
    1  2  3 
    4  5  6 
    7  8  9 
len = 
    1  1  3 % Cumulative lengths 
idx = 
    1  0  1 % Ones at start 
idx = 
    1  2  2 % Flat indexes - should be [1 3 3] 
nf = 
    11 12 13 % Numbers expanded 
repeated_num_faces = 
    11 12 12 % Wrong .numbers - should be [11 13 13] 
+0

好的。如果你確保'data(i).array'爲空,那麼'data(i).number'也是空的,矢量化的代碼將用於空'data.array'。否則,數字映射與數組長度不一致。 – angainor

回答

2

嘛,struct是不是最容易對付這裏。當然,你不應該使用repmat。而不是,預分配data_number陣列,並做了for循環:

tic; 
data_array = [data(:).array]; 
data_number = zeros(size(data_array)); 
start = 1; 
for i=1:N 
    nel = data(i).len; 
    data_number(start:start+nel-1) = data(i).number; 
    start = start+nel; 
end 
toc; 

下面是使用cumsum標記的索引在「平坦」矢量

tic; 
data_array = [data.array]; 
data_number = zeros(size(data_array)); 

% cumulative sum of number of elements in every array 
len = cumsum([data.len]); 

% mark the end of every array in a 'flat' vector 
data_number(len) = 1; 

% compute 'flat' indices for every data(i).array 
data_number = cumsum([1 data_number(1:end-1)]); 

% extract the data.number field 
data_num = [data.number]; 
data_number = data_num(data_number); 
toc; 

另一「矢量」溶液對於數據一套N=1e5次是:

Elapsed time is 0.153539 seconds. 
Elapsed time is 0.110694 seconds. 
+0

'0.35s'在我的身上,使用1e5分!好得多 - 非常感謝你! –

+1

@AlexL您可能想要更正代碼 - 缺少「-1」。我還添加了一個類似的表演「矢量化」版本。 – angainor

+0

在你的'向量化'解決方案中,我認爲你認爲''是正確的。數字'是它在數組中的索引? –