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]
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
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
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!
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