Reputation: 137
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];
Expected Output Cell Array (one column):
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
Matrix B includes which columns should be used to execute the condition on Matrix A. For example, first row of B is 3 and 5; so elements between 3rd and 5th column of matrix A should be used to execute the condition. Second row of B is 2 and 6; so elements between 2nd 6th column should be used to execute the condition. And so on...
The condition: sum specified elements and then replace all elements of the related row with the calculated sum. For example, A includes 0,0,4 (sum is 0+0+4=4), so write 4 to all elements of first row of matrix C.
Without for loop, only with matrix operations, how can I do this task?
Upvotes: 2
Views: 100
Reputation: 3898
Another variant of @Divakar's arrayfun
I dont think it would be efficient than that, as this one uses anonymous function instead of in-built colon(:)
operator
Only good news is, its a one liner
out = repmat(arrayfun(@(x,y,r) sum(A(r,x:y)),B(:,1),B(:,2),(1:size(A,1)).'),1,size(A,2))
Results for the sample input:
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
Upvotes: 2
Reputation: 221574
One approach based on 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))
Please note that repelem
is only supported in MATLAB 2015a
. So, if you don't have access to it, you can use a custom one as listed in this answer
to calculate id
alternatively like so -
id = repelem_custom(1:size(B,1),diff(B,[],2).'+1)
The custom function to replace repelem
would look something like this -
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;
Upvotes: 4
Reputation: 112679
With 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);
Upvotes: 3