3

I have an n*n matrix and I want to extract every 3 columns and keep the result in different variables.

I know that it is possible to do it in this way:

A1 = A(:,1:3); A2 = A(:,4:6); A3 = A(:,7:9); 

But I would like to simplify and automate this for managing a large amount of data!

A = [1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81] 

Expected result:

A1 = [1 2 3 2 4 6 3 6 9 4 8 12 5 10 15 6 12 18 7 14 21 8 16 24 9 18 27] A2 = [4 5 7 8 10 12 12 15 18 16 20 24 20 25 30 24 30 36 28 35 42 32 40 48 36 45 54] A3 = [7 8 9 14 16 18 21 24 27 28 32 36 35 40 45 42 48 54 49 56 63 56 64 72 63 72 81] 
2
  • 6
    Putting subsets of an existing matrix into different variables is a very inefficient way to do things and will lead to longer and more confusing code. Why do you not want to use the A(:, 1:3) syntax (or even with a variable, A(:, c:c+2))? What do you intend to do with these variables after you've created them all? Commented Aug 15, 2017 at 15:51
  • I'm assuming A2 should start 4 5 6...? Commented Aug 17, 2017 at 1:46

4 Answers 4

6

You really shouldn't split A this way. If you really want to adress A in 3 column block then use something like

A = (1:9).*((1:9).'); %% create anonymous function which can be called as Ac(1), Ac(2) and so on Ac = @(n) A(:,(n-1)*3+1:n*3) octave:2> Ac(1) ans = 1 2 3 2 4 6 3 6 9 4 8 12 5 10 15 6 12 18 7 14 21 8 16 24 9 18 27 octave:3> Ac(2) ans = 4 5 6 8 10 12 12 15 18 16 20 24 20 25 30 24 30 36 28 35 42 32 40 48 36 45 54 
Sign up to request clarification or add additional context in comments.

2 Comments

This is the best one so far, but it should be noted that this does not allow assignment to the variable A or Ac() and does not reflect changes made to A after the anonymous function is created.
I've suggested a solution to the second of these issues in my answer
4

You can use:

C = mat2cell(A,size(A,1),ones(size(A,2)/3,1)*3); 

It will split your matrix into subcells.

You can access the information contained by those cells with:

C{1} C{2} %and so on 

Comments

4

Summary

You have a few options

  • Using eval. Don't do this, it's bad practise. However, it does directly answer your question in case you were curious how to do it. Because you shouldn't use this, I've included it last!
  • Using cell arrays or matrices. This is how I would do it, although if your data set is very large you may get memory issues. It does make indexing very simple, and allows you to over-write sections of the array.
  • Using an anonymous function as shorthand for your indexing. This is a read-only way to quickly access your data, and has no memory footprint.

Using cell arrays and 3D matrices

As suggested by Mathworks in the above linked blog, you could store the partitions in a cell array...

myCellArray = cell(size(A,2)/3,1) for n = 1:3:size(A,2) myCellArray{1+(n-1)/3} = A(:,n:n+2) end % For accessing: myCellArray{1} % = A1 

or use a 3D matrix

% option 1 my3DArray = reshape(A,9,3,[]); % option 2 (same structure as above cell example) my3DArray = zeros(size(A,1), 3, size(A,2)/3); for n = 1:3:size(A,2) my3DArray(:,:,1+(n-1)/3) = A(:,n:n+2); end % For accessing: my3DArray(:,:,1); % = A1 

The best option is not to duplicate A in memory and just index it as needed, either directly or using a helper function as shown above.


Using an anonymous function

You can create a function which just essentially lets you write in short hand if this is a common indexing operation. Inline functions written with the @() notation are called anonymous functions.

% Create A A = repmat(1:9, 9, 1); % Create helper function An = @(n) A(:,(n-1)*3+1:n*3); % For accessing: An(1); % An(1) = [1 2 3; 1 2 3; ...] 

However, you cannot assign using this.

An(1) = [11 12 13; 11 12 13; ...] % wont work 

And you may be surprised if you change A then try and use it.

% Change A A = repmat(11:19, 9, 1); % A = [11 12 13 14 15 16 17 18 19; 11 12 ...] % indexing An(1); % An(1) = [1 2 3; 1 2 3; ...] not the new values!! 

To get around this second point, we could also pass A into the helper function:

An = @(M,n) M(:,(n-1)*3+1:n*3); A = repmat(1:9, 9, 1); An(A,1); % An(1) = [1 2 3; 1 2 3; ...]; A = repmat(11:19, 9, 1); An(A,1); % An(1) = [11 12 13; 11 12 13; ...]; as desired! 

Using eval

You can easily assign the variables like so

% Create some 9x9 matrix A A = repmat(1:9, 9, 1); % Loop through A, create A1, A2, ... for n = 1:3:size(A,2) eval(['A', num2str(1+(n-1)/3), ' = A(:,n:n+2)']); end % Gives the result % A1 = [1 2 3; 1 2 3; ...], A2 = [4 5 6; 4 5 6; ...], ... 

This is very bad practise in MATLAB

Please read this post by Mathworks on avoiding eval. There is no reason why setting up variables in this way is better than any other method.

  • You won't know how many variables you're making
  • You won't know all the variable names you've generated
  • You've duplicated your "big amount of data" in memory
  • eval is harder to debug when things (inevitably) go wrong!

Comments

3

Don't create dynamic variables. If really needed, reshape A into a 3D array as follows:

A = reshape(A,size(A,1),3,[]); %where 3 is the number of columns you want to extract at a time 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.