Clever solution sought: Summing values from an array into a vector component given in a second array

1 view (last 30 days)
I have two arrays -- an array of indices and an array of values, both are K x M. The index array has values between 1:M. Now I want to obtain the vector whose jth component is sum( valArray( indArray == j ) ).
Can you think of way to do this that beats the simple for loop solution? I have a couple of bsxfun solutions to do the ( indArray == j ) in one shot, but those don't beat the for loop. I also have a way to do this using a sparse array, but that doesn't beat the for loop either.
Here's code to set up the problem and find the answer using a for loop:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%NOTE: set M and K to be much larger for the real problem
M = 10;
K = 5;
indArray = randi(M,[K M]);
valArray = rand([K M]);
result = zeros(M,1);
for ii = 1 : M * K
temp = indArray(ii);
result(temp) = result(temp) + valArray(ii);
end
Thanks for taking a look.

Accepted Answer

Peter Perkins
Peter Perkins on 22 Aug 2014
I think you are looking for accumarray.

More Answers (2)

Roger Stafford
Roger Stafford on 22 Aug 2014
You might try using accumarray:
A = accumarray(indArray(:),valArray(:),[M,1]);

per isakson
per isakson on 22 Aug 2014
Edited: per isakson on 22 Aug 2014
Yes, accumarray beats the loop for large arrays (R2013a)
M = 2e3;
K = 5e3;
ix = randi(M,[K,M]);
val = rand([K,M]);
tic
out = zeros(M,1);
for ii = 1 : M * K
out(ix(ii)) = out(ix(ii)) + val(ii);
end
toc
tic
acc = accumarray( ix(:), val(:), [], @sum );
toc
assert( all( abs(out-acc)<1e-6 ), 'A:B:C', 'Results differ' )
returns
Elapsed time is 0.330848 seconds.
Elapsed time is 0.179041 seconds.
&nbsp
However
M = 100;
K = 40;
returns
Elapsed time is 0.000125 seconds.
Elapsed time is 0.000258 seconds.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!