2017-09-18 1 views
3

J'ai un struct imbriqué a de la forme suivanteConvertir struct imbriqué à réseau de cellules en utilisant le vecteur contenant la longueur des cellules

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 

Est-il possible de mettre les valeurs 1:a(i).Size de b dans un réseau de cellules sans utiliser pour boucle et sans cellfun?

Le résultat devrait ressembler à ceci:

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

Quel est le problème avec la solution actuelle? – excaza

+0

La solution actuelle utilise une boucle for que je voudrais éviter car 'cells' est habituellement autour de 50000. – evolved

+0

Une solution rapide peut être de créer un fichier mex. – m7913d

Répondre

4

j'ai donc essayé d'améliorer votre code un peu et vous pouvez voir les résultats ci-dessous:

%% 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 

Bien que cette n'évite pas la boucle for, il a un temps d'exécution légèrement meilleur. Les temps d'exécution (aux cellules = 50000) que j'ai eu étaient: @yourapproach = 0.0889, @myapproach = 0.0721, @rahnema1 = 0.2329

Ce qui suit est le code que j'ai utilisé pour résoudre ce problème. J'ai aussi apporté quelques améliorations au code que vous utilisez pour générer a (Marqué par un commentaire)

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 

Edit: J'ajoute l'approche arrayfun, mais il est au moins 10 fois plus lent que la boucle for

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

Merci pour la comparaison des différentes approches! Pourriez-vous s'il vous plaît fournir une solution en utilisant cellfun? – evolved

+1

J'ai ajouté le code 'arrayfun' mais c'est très lent. – anyanwu

1

Voici une solution sans boucle. Vous pouvez comparer avec votre approche pour voir la sorcière est plus efficace:

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' utilise plusieurs boucles 'for' en interne ainsi que la vérification des erreurs. Il est hautement improbable d'être plus rapide que la boucle nue. – excaza

+0

@excaza Cela peut être utile pour un utilisateur d'Octave. mat2cell est mieux que la boucle dans Octave. Vous pouvez [essayer] (http://rextester.com/OUF13098) – rahnema1

+1

Cependant le plus efficace dans Octave est 'c = cellslices (dat = [ab], s = 1: 40: numel (dat), s + [un .Size] -1); ' – rahnema1