Skip to Main Content Skip to Search
File Exchange
MATLAB Newsgroup
Link Exchange
  Blogs  
 Contest 
MathWorks.com

Loren on the Art of MATLAB

November 10th, 2006

All about the Colon Operator

I have written several blog articles that cover some aspects of the : operator. Based on some recent posts to the MATLAB newsgroup, it seems worthwhile for me to compile the information.

Contents

Uses of :

There are several ways that you can use the : operator in MATLAB, and they serve different purposes. Most, but not all of them, have to do with indexing into an array.

  • Creating a list of numbers
  • Collapsing trailing dimensions (right- or left-hand side)
  • Creating a column vector (right-hand side behavior related to reshape)
  • Retaining an array shape during assignment (left-hand side behavior)
  • Working with all the entries in specified dimensions

Creating a List of Numbers

You can use the : operator to create a vector of evenly-spaced numbers. Here are the integers from -3 to 3.

list1 = -3:3
list1 =
    -3    -2    -1     0     1     2     3

Here are the first few odd positive integers.

list2 = 1:2:10
list2 =
     1     3     5     7     9

Here's how to divide the interval between 0 and pi into equally spaced samples.

nsamp = 5;
sliceOfPi = (0:1/(nsamp-1):1)*pi
sliceOfPi =
         0    0.7854    1.5708    2.3562    3.1416

Note that even though only a few digits of each value in sliceOfPi are printed out, they are double precision numbers. To see more digits, check out the function format.

Collapsing Trailing Dimensions

I have a 4-dimensional array and would like to find the sum of all the elements that are in the final row and column.

b = rand(3,2,6,4);
b32sum = sum(b(3,2,:))
b32sum =
   11.4622

If instead, I sum using all the dimensions, in this case, I get a 1x1x1x4 array instead of scalar output. If I sum these output values, I get my overall sum.

b32sumAll = sum(b(3,2,:,:))
overall = sum(b32sumAll)
b32sumAll(:,:,1,1) =
    2.8279
b32sumAll(:,:,1,2) =
    3.4177
b32sumAll(:,:,1,3) =
    1.9352
b32sumAll(:,:,1,4) =
    3.2815
overall =
   11.4622

Creating a Column Vector

Here's the size of the array b32sumAll.

size(b32sumAll)
ans =
     1     1     1     4

If I want to transform this into a column vector, I can use reshape, permute or : on the right-hand side.

b32vecR = reshape(b32sumAll,[],1);
b32vecP = permute(b32sumAll, [4 1:3]);
b32vec = b32sumAll(:)
allthesame = isequal(b32vec, b32vecP, b32vecR)
b32vec =
    2.8279
    3.4177
    1.9352
    3.2815
allthesame =
     1

Retaining Array Shape During Assignment

Now let me pour some new values into b32sumAll, the array that looks almost like a vector.

b32sumAll(:) = [1 2; 3 5]
b32sumAll(:,:,1,1) =
     1
b32sumAll(:,:,1,2) =
     3
b32sumAll(:,:,1,3) =
     2
b32sumAll(:,:,1,4) =
     5

Notice that I only have to have the same number of elements on both the left- and right-hand sides. The values are poured in from the right-hand side ordered as if that array had been turned into a column vector. Note that a scalar for the right-hand side is also acceptable and then MATLAB performs a scalar expansion to fill the left-hand side.

Working with All the Entries in Specified Dimensions

If I want to manipulate values in some specific dimensions, I can also use the : operator to specify the dimensions I'd like to leave alone. For example, suppose I want to perform a left shift on the values in the second dimension of my 3-D array. Let me first create an array for illustration.

a3 = zeros(2,3,2);
a3(:) = 1:numel(a3)
a3(:,:,1) =
     1     3     5
     2     4     6
a3(:,:,2) =
     7     9    11
     8    10    12

Now let's shift the column values all over to the left, and have the right-most one become the last column. Note that columns are dimension 2. Here's a way to do this.

a3r1 = a3(:,[2:size(a3,2) 1],:)
a3r1(:,:,1) =
     3     5     1
     4     6     2
a3r1(:,:,2) =
     9    11     7
    10    12     8

How do I do this if the array could be any number of dimensions, not just 3? I can't index with :, because I don't know how many : to use, since I don't knwo the dimension. In this case, use the string value ':', create the indices in a cell array, and use the notion of the comma-separated list to perform the actual indexing. For a3, here's what this looks like.

indices = {':', [2:size(a3,2) 1],':'}
a3rnew = a3(indices{:})
sameshifts = isequal(a3r1, a3rnew)
indices = 
    ':'    [1x3 double]    ':'
a3rnew(:,:,1) =
     3     5     1
     4     6     2
a3rnew(:,:,2) =
     9    11     7
    10    12     8
sameshifts =
     1

Now, more generally, when the number of dimensions is not known, I simply create a cell array of all ':' string values, replace the specific dimensions I care about with some other indexing expression, and then I can use the index cell array to do the operation.

a5 = zeros(2,5,2,3,4);
a5(:) = 1:numel(a5);
indices = repmat({':'}, 1, ndims(a5));
myshift = [2:size(a5,2) 1]
indices{2} = myshift
a5new = a5(indices{:});
myshift =
     2     3     4     5     1
indices = 
    ':'    [1x5 double]    ':'    ':'    ':'

Let's compare two "rows" and see that the values have shifted left by 1 column.

a5(1,:,2,2,3)
a5new(1,:,2,2,3)
ans =
   151   153   155   157   159
ans =
   153   155   157   159   151

Related Reference Material

For more in depth understanding of the various ways in which the : operator can be used, look in the MATLAB documention

and in related blog articles

: is Complicated

The : operator behaves differently in MATLAB depending on its usage. This can lead to confusion. Have I missed anything major on this topic? Let me know.


Get the MATLAB code

Published with MATLAB® 7.3

11 Responses to “All about the Colon Operator”

  1. mark replied on :

    It might be nice to provide some information about how : is ordered with respect to other math operations. i.e. 1:N+1 vs (1:N)+1. This doesn’t appear to be covered in the documentation.

  2. Loren replied on :

    Mark-

    Good question. Precedence is documented here.

    And here’s the list for good measure:

    Parentheses ()

    Transpose (.’), power (.^), complex conjugate transpose (’), matrix power (^)

    Unary plus (+), unary minus (-), logical negation (~)

    Multiplication (.*), right division (./), left division (.\), matrix multiplication (*), matrix right division (/), matrix left division (\)

    Addition (+), subtraction (-)

    Colon operator (:)

    Less than (< ), less than or equal to (<=), greater than (>), greater than or equal to (>=), equal to (==), not equal to (~=)

    Element-wise AND (&)

    Element-wise OR (|)

    Short-circuit AND (&&)

    Short-circuit OR (||)

  3. A Brook replied on :

    Loren,

    why in the reply
    b32sumAll(:,:,1,1) =
    2.8279
    the first two singleton dimensions are represented by “:” and the third one by “1″? Is there any real difference between the first two dimensions and the third?

  4. Loren replied on :

    Brook-

    b32sumAll is a 1×1x1×4 array and b32sumAll(:,:,1,1) is then the value of the first element in that array. Since it’s leading dimensions are 1s, you are right that I could have achieved the same result with b32sumAll(1,1,1,1).

    –Loren

  5. brad phelan replied on :

    My interest is the use of the colon operator in for loops.

    for i = 1:100
    disp(i)
    end

    I assume that the array is not pre-generated and then iterated through. In this case 1:100 does not define a range but an iterator object. This then begs the question of the ability of user defined iterator objects.

    for i = fib(10)
    …disp(i)
    end

    where fib(10) does not pre-generate the list of numbers but generates the next on demand. Addition of the python/ruby yield keyword would do the trick

    function fib( N )
    …a = 0
    …b = 1
    …for i:N
    …..t = a + b
    …..a = b
    …..b = t
    …..yield t
    …end
    end

    Using python like philosophy this would be equivalent to

    function fib( N )
    …a = 0
    …b = 1
    …t = 0
    …i = 0
    …function next()
    …..if i == N
    …….throw “finished”
    …..end
    …..t = a + b
    …..a = b
    …..b = t
    …..return t
    …end
    …return @next
    end

    As you can see the yield keyword simplifies a common nested function paradigm and makes writing iterators that behave like the colon operator much easier.

  6. mut ante replied on :

    hi all:

    my post follows the theme raised by the previous post…

    for now, withdin a for loop we can change the value of the index and still use it to do calculations. when the cicle iterations are over, the index returns to its original value and gets incremented (or decremented) before the first code line of the next iteration of the for loop.

    this as the ability to make for loops much robust to errors. on the other hand, it leads to a great disadvantage of flexibility, i.e. if we have to jump a certain iteration (if , continue; end) based on a value calculated on the previous we can’t do it has suggested by brad. we have to insert a if condition leading to a slower code….

  7. Tony replied on :

    The problem I keep running into is where I use a function to generate a matrix that I wish to take a subsample from. While it’s straightforward to use the colon notation to subsample a stored matrix, it’s not possible to use the same method for a matrix created on the fly.

    #########

    Example
    ——-

    % V is a 3157 element vector, i.e. size(V) = 3157 3

    A = reshape(R, 41, 77);
    B = A(26:41, 52:77);

    % But this creates the unnecessary matrix “A”.
    %
    % What would be more efficient, is the more direct:-

    B = [reshape(R, 41, 77)](26:41, 52:77);

    % …or similar syntax, but this type of scenario is never
    % covered in the numerous help pages devoted to colon “:”
    % notation.

    ########

    I have a dim memory that at one point I did find a half way
    elegant way to do this (I’ve had a hiatus in my matlab
    usage and am in the process of relearning…not quite the
    same as bike riding). But considering how commonly I’m
    trying to do this type of subsampling operation (and by
    extension, I guess other people are too), it seems
    surprising that I can find no easy reference to such
    operations in the literature (couple of hours checking
    reference materials, googling, etc…).

    Of course, it wouldn’t be the first time that I’ve missed
    the obvious, so feel free to berate me if this is explained
    in bold type on page 1 of the ‘Introduction to Matlab’.

  8. JMike replied on :

    Regarding the above question about the precedence of the colon operator:

    Loren, do you remember something Damian said way back when I was running around challenging colon’s precedence?

    “All in all, I think it’d be better to keep a tight colon.”

    Or something to that effect.

    Glad I could drive by and lower the signal-to-noise ratio :)

    –JMike

  9. Loren replied on :

    Tony-

    There is no direct syntax to do what you are asking:

    first = eig(magic(3))(1)
    

    but it is in our enhancement database.

    You could sort of do this via an anonymous function. Here’s the idea:

    f = @(x,ind) x(ind);
    first = f(magic(3),1)
    

    –Loren

  10. Tim replied on :

    It’s easy to create a vector of numbers using a colon operator, but do you know how to create a sequence of numbers using only a loop and no colons?

  11. Loren replied on :

    Tim-

    You could use a while loop and and index that I bump by some increment.

    maxind = 10;
    nums = zeros(1,maxind);
    ind = 0;
    while ind < maxind
       ind = ind+1;
       nums(ind) = ind;
    end
    

    and obviously you can get more elaborate with starting, ending values and increment not being 1.

    BUT, is there a reason to not use : ?

    –Loren

Leave a Reply


Loren Shure works on design of the MATLAB language at The MathWorks. She writes here about once a week on MATLAB programming and related topics.

  • J.B. Brown: Ah, and I am at fault for simply testing collinearity with the origin in the example above.
  • J.B. Brown: Indeed, > collinear( [0 3],[0 8],[0 -1e21+2e-15] ) ans = 1 > collinear( [0 3],[0 8],[0 -1e22+2e-15]...
  • OkinawaDolphin: Loren, thank you for telling me where to download timeit. Here are the two functions I just tested...
  • Loren: JB- It looks to me like Ilya’s solution and therefore yours are equivalent to the determinant. As Tim...
  • Loren: OkinawaDolphin, timeit can be downloaded from the File Exchange. Steve Eddins is the author. It does not ship...
  • OkinawaDolphin: It seems that neither R2007a nor R2007b have the function timeit, but I investigated computation time...
  • J.B. Brown: It would appear to me that Ilya Rozenfeld’s solution would be the cleanest. Just to help those who...
  • Loren: Markus- Congratulations on winning! And a nice illustration of how the size matters. Small enough, and the...
  • Markus: Hi Loren, which version is fastest also depends very much on the matrix dimensions. Look at my test function:...
  • Duncan: OkinawaDolphin, Regarding why your third example is slower than your second example, the result is in fact...

These postings are the author's and don't necessarily represent the opinions of The MathWorks.

Related Topics