Reputation: 171
I have a main matrix, say
A=magic(5);
and also a vector
v=[1;3;5;2;2];
I want to add up row-wise the elements of A in this way: add first row from the v(1)st element to the end, second row from the v(2)rd element to the end, third row from the v(3)th element to the end, and so on.
I know that I can do this using for-loop. But I want to know if there is a vectorized way to do it.
edit: Let me clarify my question with an example: Assume A and v as above.
A =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
and
v =
1
3
5
2
2
Now I want a way to get the following results:
answer =
65 % 17+24+1+8+15
37 % 7+14+16
22 % 22
55 % 12+19+21+3
54 % 18+25+2+9
Upvotes: 4
Views: 247
Reputation: 38032
I know it's kinda cheating, but how about:
S = arrayfun(@(ii) sum(A(ii, v(ii):end)), 1:size(A,1)).';
Usually I'm a bit weary when using arrayfun
, but when comparing:
% sample data
N = 5000;
A = magic(N);
v = randi(N, N,1);
% simple loop
tic
S = zeros(N,1);
for ii = 1:N
S(ii) = sum(A(ii, v(ii):end));
end
toc
% arrayfun solution
tic
S = arrayfun(@(ii) sum(A(ii, v(ii):end)), 1:N).';
toc
% Shai's solution
tic
[m n] = size(A);
fA = fliplr(A);
fv = n + 1 - v;
csA = cumsum( fA, 2 );
res = csA( sub2ind( [m n], 1:m, fv.' ) ).';
toc
Results:
Elapsed time is 0.386280 seconds. % simple loop
Elapsed time is 0.473916 seconds. % arrayfun
Elapsed time is 0.495794 seconds. % Shai's solution
So, arrayfun
's not too bad after all.
But there is an important point here: Just look at the implementations from a distance. How easy to read/understand was the loop solution? How about the vectorized solutions?
With this in mind, also look at the performances. That's for a 5000x5000 matrix...that's 25 million elements there...
Now, would you really want to avoid that loop?
Upvotes: 3
Reputation: 114796
You can use cumsum
along the rows. The solution is a bit complex, so I'll start with a simpler example:
Suppose you want to sum all elements of the i
-th row of A
till (including) the v(i)
-th place: res_i = \sum_{k=1..v(i)} A_ik
m = size(A,1); % num of rows
csA = cumsum(A, 2); % cumsum along rows
res = csA( sub2ind( size(A), 1:m, v ) ); % pick the vi-th column for the i-th row
Now, for your question, since you want the sum of all elements from v(i)
to the end, we need to flip A
and change v
accordingly
[m n] = size(A);
fA = fliplr(A);
fv = n + 1 - v; % flip the meaning of v
csA = cumsum( fA, 2 );
res = csA( sub2ind( [m n], 1:m, fv ) ); % should do the trick...
Upvotes: 4