4

Let's say I have two (large) vectors a=[0 0 0 0 0] and b=[1 2 3 4 5] of the same size and one index vector ind=[1 5 2 1] with values in {1,...,length(a)}. I would like to compute

for k = 1:length(ind)
    a(ind(k)) = a(ind(k)) + b(ind(k));
end
% a = [2 2 0 0 5]

That is, I want to add those entries of b declared in ind to a including multiplicity.

a(ind)=a(ind)+b(ind);
% a = [1 2 0 0 5]

is much faster, of course, but ignores indices which appear multiple times.

How can I speed up the above code?

Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
Julian
  • 189
  • 3
  • what is the expected behaviour for an index which appears several times? would you like to perform the addition on this index only once? – ibezito May 31 '16 at 13:22
  • No, I would like to add the index as often as it appears. Just like in the for-loop above. – Julian May 31 '16 at 13:25
  • I do not understand why does a(ind)+b(ind) ignore indices which appear multiple times. – GameOfThrows May 31 '16 at 13:32
  • @GameOfThrows It's in the assignment back to `a` that causes the issue. It's like saying `a([1 1]) = [1 2]` – Suever May 31 '16 at 13:33

2 Answers2

5

We can use unique to identify the unique index values and use the third output to determine which elements of ind share the same index. We can then use accumarray to sum all the elements of b which share the same index. We then add these to the original value of a at these locations.

[uniqueinds, ~, inds] = unique(ind);
a(uniqueinds) = a(uniqueinds) + accumarray(inds, b(ind)).';

If max(inds) == numel(a) then this could be simplified to the following since accumarray will simply return 0 for any missing entry in ind.

a(:) = a(:) + accumarray(ind(:), b(ind));
Suever
  • 64,497
  • 14
  • 82
  • 101
3

Another approach based on accumarray:

a(:) = a(:) + accumarray(ind(:), b(ind(:)), [numel(a) 1]);

How it works

accumarray with two column vectors as inputs aggregates the values of the second input corresponding to the same index in the first. The third input is used here to force the result to be the same size as a, padding with zeros if needed.

Luis Mendo
  • 110,752
  • 13
  • 76
  • 147