oarar
oarar

Reputation: 137

Summing elements of different range for each row and replace

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

Answers (3)

Santhan Salai
Santhan Salai

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

Divakar
Divakar

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

Luis Mendo
Luis Mendo

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

Related Questions