假设我有一个矩阵C1,C2
,如下所示:
C1 = nx2 cell
每个单元格为[5x5 double]
。
C2 = 1x1 cell
包含[5x5 double]
。
如何将C3
计算为:
C3{1,1} = C1{1,1}+C2{1,1};
C3{1,2} = C1{1,2}+C2{1,1};
.
.
C3{n,2} = C1{n,2}+C2{1,1};
使用cellfun
或任何其他方法而不循环
答案 0 :(得分:3)
对于那些具有常规大小数组的情况,您最好使用多维数组而不是慢速数组。虽然坚持使用单元阵列,但这里是一个矢量化解决方案,使用bsxfun
作为矢量化广播求和的基础,然后将它们转换为多维数组 -
%// Store size of each cell and size of C1 for later reshaping purposes
[m,n] = size(C1{1,1})
[nr,nc] = size(C1);
%// Perform broadcasted summations with BSXFUN
sums = bsxfun(@plus,cat(3,C1{:}),C2{1,1})
%// Reshape and convert back to cell arrays as desired output
out = reshape(mat2cell(sums,m,n,ones(1,nr*nc)),nr,nc)
答案 1 :(得分:2)
直接使用cellfun
可以完全满足您的需求:
C3 = cellfun(@(x) x+C2{1,1},C1,'uniformoutput',false);
这将基本上循环遍历单元格数组C1
的每个元素,并且对于每个元素应用匿名函数@(x) x+C2{1,1}
,即每个元素将添加到C2{1,1}
。生成的元素将返回与C1
大小相同的单元格数组。
对于一些较小的测试用例,我将此解决方案与suggested by @Divakar进行了比较。结果并非微不足道,因为cellfun
和cat
(在Divakar的解决方案中使用)都很慢。我扔了第三个版本进行检查,我在匿名函数中定义了一个临时变量:
tmpvar=C2{1,1};
C3a2=cellfun(@(x) x+tmpvar,C1,'uniformoutput',false);
这背后的基本原理是访问单个单元格元素应该有一些开销,我不确定整个单元格是否被拉入匿名函数的工作区。
我定义了一个单独的函数来测试这三种情况,以便让JIT完成它的工作(但请注意,我使用的是R2012b,较新的版本可能会产生完全不同的结果,the new execution engine and everything)。我在相同的随机输入上运行了所有三种情况(大小为C2
的{{1}}单元格数组,并且包含与[1,1]
大小相同的数组),从10次尝试中选择最短的运行时间(基于C1{k,l}
)。
tic/toc
5x5
矩阵的单元格数组:
10x10
:cellfun
0.000452 s
+ cellfun
:tmpvar
0.000287 s
:bsxfun(cat)
0.002970 s
5x5
矩阵的单元格数组:
100x100
:cellfun
0.000988 s
+ cellfun
:tmpvar
0.000963 s
:bsxfun(cat)
0.004661 s
10x10
矩阵的单元格数组:
5x5
:cellfun
0.001580 s
+ cellfun
:tmpvar
0.000945 s
:bsxfun(cat)
0.011358 s
100x100
矩阵的单元格数组:
5x5
:cellfun
0.108276 s
+ cellfun
:tmpvar
0.082675 s
:bsxfun(cat)
根据这些小测试案例,我很想得出结论
1.132417 s
的匿名函数中使用临时变量确实可以计算出较大的单元格数组是否大,这是有意义的(从那时起,该函数被评估的次数更多)。cellfun
的解决方案对于小型单元阵列来说有点慢,对于较大的单元阵列则慢得多。我怀疑bsxfun(cat)
应该归咎于cat
将额外的维度放在一起需要很多。我甚至可以想象,使用预分配的循环可能会胜过cat
。cat
)矩阵和单元阵列检查相同内容会很有趣。