2

I want to create a vector containing the group identifier for each element from a vector containing the number of elements in each group.

Example:

E = [2 3 4]'

I am looking for a vector as follows:

I = [1 1 2 2 2 3 3 3 3]

I found one solution involving a loop:

I = [];
for e=1:size(E,1),
    I = [I ; e*ones(E(e),1)];
end

But this doesn't seem very elegant. Any advice for improvements are welcome.

Shai
  • 111,146
  • 38
  • 238
  • 371
  • Google for runlength decoding, see here: http://www.mathworks.com/matlabcentral/fileexchange/41813-runlength – Nras Aug 07 '14 at 08:57

3 Answers3

3

You are looking for run length decoding.
Try this

n = sum( E ); %// tot number of elelments
I = zeros( 1, n ); % //preallocate!
I(cumsum( [ 1 E(1:end-1) ] ) ) = 1;
I = cumsum( I )

See a running example at ideone.

Shai
  • 111,146
  • 38
  • 238
  • 371
  • If I run your code with `E = [2 3 4]` it does not return the expected result. Guess sth. went wrong. – The Minion Aug 07 '14 at 09:03
  • @TheMinion please see my edit and the running example at ideone. – Shai Aug 07 '14 at 09:03
  • Your code still doesn't work completely right. I used `E=ceil(rand(1,1000)*10);` and the resulting vector first of all doesn't have the right numbers of `1,2` (didn't check further) nor does it go til `1000` but stops somewhere before. – The Minion Aug 07 '14 at 09:19
  • 1
    @Shai I did some testing with a much larger vector and your code is by far the fastest! Thank you! – TiredHornet Aug 07 '14 at 09:20
  • 1
    @TiredHornet in my test the result was off. You should doubelcheck the data. My `E=[4, 4, 10, ...]` resulting `I= [1 1 1 2 2 2 2 2 2 2 2 2 3 3 ...]`. Thus the construced `E=[3, 9, 7,...]` is wrong. As commented above my test function was: `E=ceil(rand(1,1000)*10);` – The Minion Aug 07 '14 at 09:23
  • @TheMinion Thank you for the hint. I somehow overlocked that. After checking again I also don't get the right results. So actually thewaywewalk's solution is probably best. – TiredHornet Aug 07 '14 at 09:40
  • @TiredHornet - indeed a bug. fixed it. please try again. you can play with it in [ideone](http://ideone.com/SFUC1e). – Shai Aug 07 '14 at 09:45
  • @TheMinion thanks for spotting my bug! fixed it and it should be ok now. . you can play with it in [ideone](http://ideone.com/SFUC1e). – Shai Aug 07 '14 at 09:45
  • 1
    @Shai Yes your code if working just fine now and it is still way faster than all the other solutions. Well done :D and +1 – The Minion Aug 07 '14 at 09:49
2

Try this:

X = arrayfun(@(x) [1 zeros(1,x-1)], E, 'uni',0)
Y = cumsum( [X{:}] )
Robert Seifert
  • 25,078
  • 11
  • 68
  • 113
0

I had a similar problem. I think, without using a for-loop, it's not as simple as one could think.

Here is my solution:

I = cell2mat(arrayfun(@(x) repmat(x,E(x),1),1:numel(E),'UniformOutput',false)') 

Some explanation: x is the Index of E. The array-function "iterates" from 1 to numel(E). repmat replicates the index x E(x) times. The Output of the array-function is a 1x3-Cell array with vectors [11], [222] and [3333]. Because of the different vector sizes, I have to set the Uniformoutput to false. But I want to concatenate these nested vectors, so I use cell2mat(...)

Bibonaut
  • 61
  • 5