2

I have a matrix:

mat = [  2009 3 ;
         2010 2 ] ;

I need to repeat the Col1 as per Col2. The solution at Repeat copies of array elements: Run-length decoding in MATLAB is helpful. However, my main problem is to then increment the years according, as in:

Ansmat = [  2009 3
            2010 3
            2011 3
            2010 2
            2011 2 ] ;

I want to avoid a for loop here. Thanks for your help! This would be a great help!

Community
  • 1
  • 1
Maddy
  • 2,520
  • 14
  • 44
  • 64

3 Answers3

2

You can first replicate your matrix using my vectorized answer to the previous question:

>> mat = [2009 3; 2010 2];
>> index = zeros(1, sum(mat(:, 2)));
>> index([1; cumsum(mat(1:end-1, 2))+1]) = 1;
>> Ansmat = mat(cumsum(index), :)

Ansmat =

        2009           3
        2009           3
        2009           3
        2010           2
        2010           2

Next, you can create a column vector of offsets to add to the dates in the first column. Here's how you can do this in a vectorized way.

>> offset = ones(size(Ansmat, 1), 1);
>> offset([1; cumsum(mat(1:end-1, 2))+1]) = [0; 1-mat(1:end-1, 2)];
>> Ansmat(:, 1) = Ansmat(:, 1)+cumsum(offset)

Ansmat =

        2009           3
        2010           3
        2011           3
        2010           2
        2011           2
Community
  • 1
  • 1
gnovice
  • 125,304
  • 15
  • 256
  • 359
  • 1
    Wow, that is an insanely clever and smart way, kudos :) A minor correction; so this works for a matrix with more than two lines you need to transpose mat(1:end-1, 2) in the three places where you use it in the [1 ...] context. – GummiV Mar 27 '12 at 18:12
  • @GummiV: Good catch. I added some semicolons to correct the dimension mismatches that would occur for larger matrices. – gnovice Mar 27 '12 at 18:17
  • @Gnovice thanks. I had noted the error as mentioned by GummiV and corrected it with a simple ; Thanks..this is really fast and clever :) – Maddy Mar 28 '12 at 00:04
0

I'm not sure if there is a way to do this without a loop since this is a somewhat obscure operation we're performing. If I understand your algorithm correctly here are two methods that use a single for loop:

B = zeros(sum(A(:,2)), 2);
counter = 1;
for i = 1:size(A,2)
    n = A(i,2);
    B(counter:counter+n-1,1) = A(i,1)+(0:n-1)';
    B(counter:counter+n-1,2) = n;
    counter = counter+n;
end

You could do away with the preallocate. If the counter variable is confusing then you could check out this one which appends the matrix B every iteration but needs an inital starting-case instead.

n = A(1,2);
B = [A(1,1)+(0:n-1)', n*ones(n,1)];
for i = 2:size(A,2)
    n = A(i,2);
    B = [B; A(i,1)+(0:n-1)', n*ones(n,1)];
end
GummiV
  • 216
  • 2
  • 6
0
incr = (0 : max(mat(:, 2)))';
incr = [incr, 0 * incr];
Ansmat = [];
for k = 1 : size(mat, 1)
    Ansmat = cat(1, Ansmat, repmat(mat(k, :), mat(k, 2), 1) + incr(1 : mat(k, 2), :));
end

But if the expected size of matrix Ansmat is large, the first solution of GummiV will be faster.

Serg
  • 13,470
  • 8
  • 36
  • 47