0

This is a basic program but since I'm new to MATLAB, I'm not able to figure out the solution.

I have a column vector "Time" in which I want to print value "1" in first 147 cells, followed by "2" in 148 to 2*147 cells and so on. For that, I have written the following script:

 Trial>> c=1;
 Trial>> k=0;
 Trial>> for i = c:146+c
            Time(i,1)=1+k;
            c=i;
            k=k+1;
            end

I know I need to iterate the loop over "Time(i,1)=1+k;" before it executes the next statement. I tried using break but that's not supposed to work. Can anyone suggest me the solution to get the desired results?(It was quite simple in C with just the use of curly braces.)

shitty_coder
  • 123
  • 3
  • 15
  • i don't quite understand what you want. the output is expected to be `121212...` or `111..11222..222`? Matlab's for-loop is a linear iteration, your for-loop structure is a bit weird . – Gnimuc Jun 23 '16 at 04:48

4 Answers4

3

I am sure you don't want to run c=i; in every iteration.

My code should work for you:

x = 10; % Replace 10 by the max number you need in your array.
k = 1;
for i = 1 : x * 147
    Time(i, 1) = k;
    if rem(i, 147) == 0
        k = k + 1;
    end
end
TangKe
  • 378
  • 1
  • 11
  • 3
    @dora Please consider the other answers as well. Although this is a correct solution, I think it is the worst one posted (in terms of efficient use of Matlab) – Bernhard Jun 23 '16 at 07:07
3

This is the prime example of a piece of code that should be vectorized can help you understand vectorization. Your code can be written like this:

n = 147;
reps = 10; %% Replace this by the maximum number you want your matrix to have

Time = reshape(bsxfun(@plus, zeros(n,1), 0:reps), 1, []);

Explanation:

Let A be a column vector (1 column, n rows), and B be a row vector (1 row, m columns.

What bsxfun(@plus, A, B) will do here is to add all elements in A with all elements in B, like this:

A(1)+B(1)  A(1)+B(2)  A(1)+B(3) ... A(1)+B(m)
A(2)+B(1)  A(2)+B(2)  ............. A(2)+B(m)
............................................
A(n)+B(1)  A(n)+B(2) .............. A(n)+B(m)

Now, for the two vectors we have: zeros(n,1), and 0:reps, this will give us;

0+0        0+1        0+2           0+reps
0+0        0+1        0+2           0+reps
% n rows of this

So, what we need to do now is place each column underneath each other, so that you will have the column with zeros first, then the row with ones, ... and finally the one with reps (147 in your case).

This can be achieved by reshaping the matrix:

reshape(bsxfun(@plus, zeros(n,1), 0:reps), [], 1);
^       ^                                  ^   ^
|       |                                  |   Number of rows in the new matrix. When [] is used, the appropriate value will be chosen by Matlab
|       |                                  Number of rows in the new matrix
|       matrix to reshape
reshape command   

Another approach is using kron:

kron(ones(reps+1, 1) * 0:(n-1)

For the record, a review of your code:

You should always preallocate memory for matrices that are created inside loops. In this case you know it will become a matrix of dimensions ((reps+1)*n-by-1). This means you should do Time = zeros((reps+1)*n, 1);. This will speed up your code a lot.

You shouldn't use i and j as variable names in Matlab, as they denote the imaginary unit (sqrt(-1)). You can for instance do: for ii = 1:(n*147) instead.

You don't want c=i inside the loop, when the loop is supposed to go from c to c + 146. That doesn't make much sense.

Stewie Griffin
  • 14,889
  • 11
  • 39
  • 70
  • Do you really think `bsxfun` with `reshape` is the best solution? What about just `a=floor((0:(n*reps-1))/n)` (which is quicker) – Bernhard Jun 23 '16 at 06:47
  • 2
    `bsxfun` with `reshape` is **always** the best solution. `bsxfun` with `reshape` and `permute` is the second best one... Unless there are better faster alternatives of course. =P I suggest you post that as an answer, you'll have my upvote! I didn't think of it, and yes, it might be better than mine. In my opinion it's a bit harder to read though, but not much. – Stewie Griffin Jun 23 '16 at 06:52
  • I can of readability, I am always confused with `bsxfun` :) – Bernhard Jun 23 '16 at 07:02
  • Well, I always have to think about rows and columns, `rdivide` and `ldivide`. In combination with `reshape` kind of things I never have it right at the first try, and I bet your first try wasn't correct either ;) – Bernhard Jun 23 '16 at 07:17
  • 1
    Nope, my first try was far from correct. My second try however was ... wrong too. I guess I might have been right at the tenth attempt, and again at the 20th. I had even more mistakes once I included `permute` in the mix... But then again, I've created countless of infinite loops, indexing errors, bottlenecks out of this world etc... I asked [this](http://stackoverflow.com/questions/16497579/finding-the-difference-between-columns-in-matrix-without-loops) question three years ago... Almost embarrassing now! I definitely didn't understand `bsxfun` those days,,, – Stewie Griffin Jun 23 '16 at 07:23
2

You can use repmat,

x = 10; % Sequence length (or what ever it can be called)
M = repmat(1:x,147,1); % Replicate array 1:x for 147 columns
M = M(:); % Reshape the matrix so that is becomes a column vector.

I can assume that this is a task to practice for loops, but this will work.

patrik
  • 4,506
  • 6
  • 24
  • 48
1

An alternative solution may be to do

n = 147;
reps = 10;
a = ceil( (1:(n*reps)) / n);

You first construct an array with the length you want. Then you divide, and round of upwards. 1 to 147 will then become 1.

Stewie Griffin
  • 14,889
  • 11
  • 39
  • 70
Bernhard
  • 3,619
  • 1
  • 25
  • 50