2017-09-18 72 views
3

我有以下形式的嵌套結構a的含有長度向量單元陣列轉換嵌套結構使用細胞

Sizes = [10, 9, 8, 11, 10]; 
cells = 5; 
for i = 1:cells 
    for j = 1:40 
     a(i).b(j) = rand(1,1); 
    end 
    a(i).Size = Sizes(i); 
end 

是否有可能把的b1:a(i).Size值到一個單元陣列,而無需使用用於循環和沒有cellfun

結果應該是這樣的:

c = cell(1,cells); 
for i = 1:cells 
    sz = a(i).Size; 
    c{1,i} = a(i).b(1:sz); 
end 
+0

目前的解決方案有什麼問題? – excaza

+0

當前的解決方案使用了一個for循環,我想避免這個循環,因爲'cells'通常在50000左右。 – evolved

+0

快速解決方案可能是創建一個mex文件。 – m7913d

回答

4

於是,我就在你的代碼提高一點點,你可以看到下面的結果:

%% My approach to solve the question (it has a slightly better runtime) 
function c = myapproach(a, cells) 
c = {a.b}; 
sz = [a.Size]; 
for i = 1:cells 
    c{i} = c{i}(1:sz(i)); 
end 
end 

雖然這不會避免for循環,它有一個稍微好一點的運行時間。我得到的運行時間(在單元= 50000)是:@yourapproach = 0.0889, @myapproach = 0.0721, @rahnema1 = 0.2329

以下是我用來解決這個問題的代碼。我也對一些代碼的改進用來生成a(通過註釋標記)

function solveit() 
cells = 50000; 
maxVal = 40; 
Sizes = randi(maxVal, 1, cells); 
a(cells) = struct('Size', 0, 'b', []); %% Improved by preallocating a 
for i = 1:cells 
    a(i).b = rand(1, maxVal); %% Improved by removing the unnecessary double loop 
    a(i).Size = Sizes(i); 
end 
fun1 = @() yourapproach(a, cells); 
fun2 = @() myapproach(a, cells); 
fun3 = @() rahnema1(a); 
%% Show runtimes 
timeit(fun1) 
timeit(fun2) 
timeit(fun3) 
c1 = fun1(); 
c2 = fun2(); 
c3 = fun3(); 
%%Show approach equivalence 
disp(isequal(c1, c2)) 
disp(isequal(c1, c3)) 
end 
%% Your approach 
function c = yourapproach(a, cells) 
c = cell(1, cells); 
for i = 1:cells 
    sz = a(i).Size; 
    c{1,i} = a(i).b(1:sz); 
end 
end 
%% Approach mentioned by rahnema1 
function c = rahnema1(a) 
cc = struct2cell(a); 
sz = [cc{1:2:end}]; 
sz = [sz;40-sz]; 
dat = [cc{2:2:end}]; 
c = mat2cell(dat, 1, sz(:)); 
c = c(1:2:end); 
end 

編輯:我加入arrayfun方法,但它比for

function c = newapproach(a) 
sz = [a.Size]; 
c = arrayfun(@(x, y) x.b(1:y), a, sz, 'UniformOutput', false); 
end 
慢至少10倍
+0

感謝您對不同方法的比較!您能否使用cellfun提供解決方案? – evolved

+1

我已經添加了'arrayfun'代碼,但它非常慢。 – anyanwu

1

這裏是沒有循環的解決方案。你可以用你的方法比較這看看女巫一個更有效:

cc=struct2cell(a) 
sz = [cc{2:2:end}]; 
sz = [sz;40-sz] 
dat = [cc{1:2:end}]; 
result = mat2cell(dat,1,sz); 
result = result(1:2:end); 
+0

'mat2cell'在內部使用多個'for'循環以及錯誤檢查。它不太可能比裸循環更快。 – excaza

+0

@excaza對於Octave用戶可能很有用。 mat2cell比Octave中的循環要好。你可以[嘗試](http://rextester.com/OUF13098) – rahnema1

+1

然而,Octave中最有效的是'c = cellslices(dat = [ab],s = 1:40:numel(dat),s + [a .Size] -1);' – rahnema1