Search code examples
indexingsumoctavevectorizationbinning

Octave: summing indexed elements


The easiest way to describe this is via example:

data = [1, 5, 3, 6, 10];
indices = [1, 2, 2, 2, 4];
result = zeroes(1, 5);

I want result(1) to be the sum of all the elements in data whose index is 1, result(2) to be the sum of all the elements in data whose index is 2, etc.

This works but is really slow when applied (changing 5 to 65535) to 64K element vectors:

result = result + arrayfun(@(x) sum(data(index==x)), 1:5);

I think it's creating 64K vectors with 64K elements that's taking up the time. Is there a faster way to do this? Or do I need to figure out a completely different approach?


for i = [1:5]
    idx = indices(i);
    result(idx) = result(idx) + data(i);
endfor

But that's a very non-octave-y way to do it.


Solution

  • Seeing how MATLAB is very similar to Octave, I will provide an answer that was tested on MATLAB R2016b. Looking at the documentation of Octave 4.2.1 the syntax should be the same.

    All you need to do is this:

    result = accumarray(indices(:), data(:), [5 1]).'
    

    Which gives:

    result =
    
         1    14     0    10     0
    

    Reshaping to a column vector (arrayName(:) ) is necessary because of the expected inputs to accumarray. Specifying the size as [5 1] and then transposing the result was done to avoid some MATLAB error.

    accumarray is also described in depth in the MATLAB documentation