为每行求和不同范围的元素并替换

时间:2015-05-30 09:42:57

标签: matlab matrix

A = [-1,-1,0,0,4,1,3,0,1,1;
     -1,1,1,0,2,1,1,0,0,1;
     0,0,1,0,1,0,1,0,2,0];

B = [3,5;
     2,6;
     1,7];

预期输出单元阵列(一列):

C = [4,4,4,4,4,4,4,4,4,4;            %// sum of elements 3,4,5 is 4
     5,5,5,5,5,5,5,5,5,5;        %// sum of elements 2,3,4,5,6 is 5
     3,3,3,3,3,3,3,3,3,3];   %// sum of elements 1,2,3,4,5,6,7 is 3

矩阵B包括应该使用哪些列来执行矩阵A上的条件。例如,B的第一行是3和5;因此,矩阵A的第3列和第5列之间的元素应该用于执行条件。 B的第二行是2和6;所以应该使用第2列之间的元素来执行条件。等等...

条件:对指定的元素求和,然后用计算的和替换相关行的所有元素。例如,A包括0,0,4(sum为0 + 0 + 4 = 4),因此将4写入矩阵C的第一行的所有元素。

没有for循环,只有矩阵运算,我该如何完成这项任务?

3 个答案:

答案 0 :(得分:4)

基于repelem@colon notation& accumarray -

id = repelem(1:size(B,1),diff(B,[],2)+1)
extents_cell = arrayfun(@colon, B(:,1), B(:,2), 'Uni', 0)

rowval = accumarray(id(:),A(sub2ind(size(A),id,[extents_cell{:}])))
C = repmat(rowval,1,size(A,2))

请注意,repelem仅支持MATLAB 2015a。因此,如果您无法访问它,则可以使用this answer中列出的自定义版本来计算id,或者像这样 -

id = repelem_custom(1:size(B,1),diff(B,[],2).'+1)

替换repelem的自定义函数看起来像这样 -

function out = repelem_custom(vals,runlens)
clens = cumsum(runlens);
idx = zeros(1,(clens(end)));
idx([1 clens(1:end-1)+1]) = diff([0 vals]);
out = cumsum(idx);
return;

答案 1 :(得分:3)

使用bsxfun

n = size(A,2);
jj = 1:n;
C = repmat(sum(A .* (bsxfun(@ge, jj, B(:,1)) & bsxfun(@le, jj, B(:,2))), 2), 1, n);

答案 2 :(得分:2)

@Divakar的arrayfun

的另一种变体

我认为它不会那么高效,因为这个使用匿名函数而不是内置colon(:)运算符

唯一的好消息是,它是一个单线

out = repmat(arrayfun(@(x,y,r) sum(A(r,x:y)),B(:,1),B(:,2),(1:size(A,1)).'),1,size(A,2))

示例输入的结果:

out =

 4     4     4     4     4     4     4     4     4     4
 5     5     5     5     5     5     5     5     5     5
 3     3     3     3     3     3     3     3     3     3