i = [1 2 3 4 5];
a = {[1 3 4 5] [5 4 3] [1 2 3] [4] [5 2]};
b = {[1] [4 2 3] [1 3] [2 1 4] [1 2 3]};
对于a
和b
,以下条件为
a
和b
的大小为i
a
和b
每个数组中的每个元素都来自i
有没有办法对以下代码进行Vectorise以避免for
循环
x = 0;
for elem = i
x = x + sum(ismember(cell2mat(a(a{elem})),b{elem}));
end
x
由于
答案 0 :(得分:1)
方法#1
我认为这样,你会在循环中遇到cell2mat
的瓶颈。如果你运行它进行相当多的循环迭代,就会感觉到这个瓶颈。因此,在这篇文章中,我将尝试重新组织输入数组a
,以便在循环外部使用cell2mat
。这将用于提取所有元素,然后将单元格元素重新分组为另一个单元格数组,每个单元格将在每次迭代时使用原始代码保存与cell2mat()
提取值相对应的值。因此,可以直接馈送这种重组的单元阵列的每个单元以替换cell2mat(a(a{elem}))
。
因此,为了实现所有这些承诺,实施将是 -
% Re-organize a to create another cell array in which each cell
% would have "cell2mat(a(a{elem}))" for iterator elem
lens = cellfun('length',a)
arr = [a{:}]
cumlens = cumsum(lens(arr))
grouped_cumlens = cumlens(cumsum(lens))
grouped_a = mat2cell(cell2mat(a(arr)),1,diff([0 grouped_cumlens]))
% Use grouped_a to perform the same operations but without cell2mat in loops
outx = 0;
for elem = i
outx = outx + sum(ismember(grouped_a{elem},b{elem}));
end
如果你迫切需要完全矢量化代码,那么loopy代码很容易用bsxfun
进行矢量化,但是我不确定这是否会提供性能优势,因为它取决于你对输入的数据格式。
方法#2
这是一种替代方法,在从a
中提取元素时仍然保留以前的版本。但是,它不是存储为另一个单元格数组,而是保留常规数组,并另外保存与每次迭代时从中提取元素的限制相对应的起始和终止索引。因此,实现看起来像这样 -
% Code un-changed from the previous version
lens = cellfun('length',a)
arr = [a{:}]
cumlens = cumsum(lens(arr))
grouped_cumlens = cumlens(cumsum(lens))
% Extract data into a regular array and decide start and stop indices
data = cell2mat(a(arr))
starts = [1 grouped_cumlens(1:end-1)+1]
stops = grouped_cumlens
% Use extracted data with its start,stop indices for each iteration
outx = 0;
for elem = i
outx = outx + sum(ismember(data(starts(elem):stops(elem)),b{elem}));
end
再次bsxfun
可以与此版本一起使用,以完全向量化这里的内容!