【问题标题】:Convert nested struct to cell array using vector containing length of cells使用包含单元格长度的向量将嵌套结构转换为单元格数组
【发布时间】:2018-02-27 00:01:09
【问题描述】:

我有一个嵌套结构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

是否可以在不使用 for 循环和不使用 cellfun 的情况下将 b1:a(i).Size 值放入元胞数组中?

结果应该是这样的:

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

【问题讨论】:

  • 目前的解决方案有什么问题?
  • 当前的解决方案使用了我想避免的 for 循环,因为cells 通常在 50000 左右。
  • 一个快速的解决方案可能是创建一个 mex 文件。
  • 你为什么不想使用cellfun
  • @m7913d cellfun 几乎总是比显式循环慢

标签: matlab for-loop cell


【解决方案1】:

所以我尝试对您的代码进行一些改进,您可以看到以下结果:

%% 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 循环慢 10 倍

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

【讨论】:

  • 感谢不同方法的比较!您能否提供一个使用 cellfun 的解决方案?
  • 我已经添加了arrayfun 代码,但是速度很慢。
【解决方案2】:

这是一个没有循环的解决方案。您可以将此与您的方法进行比较,以了解女巫一号更有效:

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);

【讨论】:

  • mat2cell 在内部使用多个 for 循环以及错误检查。它不太可能比裸循环更快。
  • @excaza 它可​​能对 Octave 用户有用。 mat2cell 比 Octave 中的循环更好。你可以try it
  • 然而在 Octave 中最高效的是c= cellslices(dat=[a.b],s=1:40:numel(dat),s+[a.Size]-1);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-14
  • 1970-01-01
  • 2014-06-06
相关资源
最近更新 更多