Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert nested struct to cell array using vector containing length of cells

I have a nested struct a of the following form

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

Is it possible to put the 1:a(i).Size values of b into a cell array without using a for loop and without cellfun?

The result should look like this:

c = cell(1,cells);
for i = 1:cells
    sz = a(i).Size;
    c{1,i} = a(i).b(1:sz);
end
like image 212
evolved Avatar asked May 16 '26 06:05

evolved


1 Answers

So i tried to improve on your code a little bit and you can see the results below:

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

Although this does not avoid the for loop, it has a slightly better runtime. The run-times (at cells = 50000) i got were: @yourapproach = 0.0889, @myapproach = 0.0721, @rahnema1 = 0.2329

The following is the code i used to solve this. I also made some improvements to the code you use to generate a (Marked by a comment)

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: I am adding the arrayfun approach but it is at least 10 times slower than the for loop

function c = newapproach(a)
sz = [a.Size];
c = arrayfun(@(x, y) x.b(1:y), a, sz, 'UniformOutput', false);
end
like image 165
ammportal Avatar answered May 19 '26 04:05

ammportal



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!