0

I have this vector:

a = [ 7 8 9 7 8 9]; 

and I would like to obtain the following vector:

b= [ 7 8 9 7 8 9; 
     17 18 19 17 18 19; 
     27 28 29 27 28 29; 
     37 38 39 37 38 39 ...]

I am replicating the vector and then summing 10 for each line (for n lines). I would like to do this without using loop iterations. How can I do it? Thank you so much.

rayryeng
  • 102,964
  • 22
  • 184
  • 193

3 Answers3

12

My first bsxfun solution.

a = [ 7 8 9 7 8 9]; 
b = 0:10:(10+10*n);
c = bsxfun(@plus,a,b.');
c =
     7     8     9     7     8     9
    17    18    19    17    18    19
    27    28    29    27    28    29
    37    38    39    37    38    39
    47    48    49    47    48    49
    57    58    59    57    58    59
    67    68    69    67    68    69
    77    78    79    77    78    79
    87    88    89    87    88    89
    97    98    99    97    98    99
   107   108   109   107   108   109

Bit of explanation, though a full and complete introduction to bsxfun can be found in this answer by Divakar.

What happens is that your row array a gets piece-wise added to the column vector b. Thus the first element of a, being 7 in this case, gets added to the column vector b=[10;20;30;...] and becomes the first column of your output matrix c. The second entry of a is summed with the same column vector b and becomes the second column of c. This gets repeated to fill the entire matrix c to a size of numel(b) x numel(a).

This is becoming quite the coding fest. I ran some bench test, running a loop with n=1000 a hundred times and averaged the results. Windows 7, MATLAB R2012a, i5-750 CPU. Actually, the for loop is not even the worst in terms of timing:

  • bsxfun: 0.00003556 s.
  • repmat: 0.00048514 s.
  • cumsum: 0.00015726 s.
  • for : 0.00033096 s.

Timing revisited on the same system, but with MATLAB R2015a. for is now the slowest, with the others edging towards one another, but bsxfun prevails!

  • bsxfun: 0.00002030 s.
  • repmat: 0.00005213 s.
  • cumsum: 0.00002180 s.
  • for : 0.00019560 s.

Where I used this for loop implementation:

base = [7 8 9 7 8 9];
A = zeros(1e3,length(base));
for n = 1:1e3;
A(n,:) = base+10*n;
end
Community
  • 1
  • 1
Adriaan
  • 17,741
  • 7
  • 42
  • 75
5

For completeness, you could also obtain the desired result through the use of the repmat command:

n = 3;
a = [7 8 9 7 8 9];
addingMatrix = repmat([0:10:10*n+1]',1,size(a,2));

b = addingMatrix + repmat(a,n+1,1);

Result:

b =

   7     8     9     7     8     9
  17    18    19    17    18    19
  27    28    29    27    28    29
  37    38    39    37    38    39
Vidar
  • 4,141
  • 5
  • 24
  • 30
3

Since repmat and bsxfun are already taken, another approach is to create a temporary array where [7 8 9 7 8 9] is the first row, followed by a matrix completely full of 10s where the number of rows is the desired number you want and the number of columns is the total number of elements in the base vector ([7 8 9 7 8 9]). You'd then apply a cumulative sum via cumsum along the rows:

n = 11; %// Number of rows - including the first row of [7 8 9 7 8 9]
base = [7 8 9 7 8 9];
A = [base; 10*ones(n-1, numel(base))];
B = cumsum(A, 1);

We get:

>> B

B =

     7     8     9     7     8     9
    17    18    19    17    18    19
    27    28    29    27    28    29
    37    38    39    37    38    39
    47    48    49    47    48    49
    57    58    59    57    58    59
    67    68    69    67    68    69
    77    78    79    77    78    79
    87    88    89    87    88    89
    97    98    99    97    98    99
   107   108   109   107   108   109
rayryeng
  • 102,964
  • 22
  • 184
  • 193