views:

280

answers:

2

My question is similar to this one, but I would like to replicate each element according to a count specified in a second array of the same size.

An example of this, say I had an array v = [3 1 9 4], I want to use rep = [2 3 1 5] to replicate the first element 2 times, the second three times, and so on to get [3 3 1 1 1 9 4 4 4 4 4].

So far I'm using a simple loop to get the job done. This is what I started with:

vv = [];
for i=1:numel(v)
    vv = [vv repmat(v(i),1,rep(i))];
end

I managed to improve by preallocating space:

vv = zeros(1,sum(rep));
c = cumsum([1 rep]);
for i=1:numel(v)
    vv(c(i):c(i)+rep(i)-1) = repmat(v(i),1,rep(i));
end

However I still feel there has to be a more clever way to do this... Thanks

+7  A: 

Here's one way I like to accomplish this:

>> index = zeros(1,sum(rep));
>> index(cumsum([1 rep(1:end-1)])) = 1;

index =

     1     0     1     0     0     1     1     0     0     0     0

>> index = cumsum(index)

index =

     1     1     2     2     2     3     4     4     4     4     4

>> vv = v(index)

vv =

     3     3     1     1     1     9     4     4     4     4     4

This works by first creating an index vector of zeroes the same length as the final count of all the values. By performing a cumulative sum of the rep vector with the last element removed and a 1 placed at the start, I get a vector of indices into index showing where the groups of replicated values will begin. These points are marked with ones. When a cumulative sum is performed on index, I get a final index vector that I can use to index into v to create the vector of heterogeneously-replicated values.

gnovice
could you add some comments of how this works?
Nathan Fellman
@Nathan: Already ahead of ya. =)
gnovice
@gnovice: definitely a clever way of using `cumsum`.. Thanks!
merv
+2  A: 

To add to the list of possible solutions, consider this one:

vv = cellfun(@(a,b)repmat(a,1,b), num2cell(v), num2cell(rep), 'UniformOutput',0);
vv = [vv{:}];

This is much slower than the one by gnovice..

Amro
You could actually use ARRAYFUN and avoid the calls to NUM2CELL, but it would still be *much* slower: http://stackoverflow.com/questions/1975772/matlab-array-manipulation/1975835#1975835.
gnovice