Suppose I had a 1-by-12 matrix and I wanted to resize it to a 4-by-3 matrix. How could I do this?
My current solution is kind of ugly:
for n = 1:(length(mat)/3)
out(n,1:3) = mat( ((n-1)*3 + 1):((n-1)*3 + 3) );
end
Is there a better way to do this?
reshape is of course the proper solution, as stated by #gnovice.
A nice feature of reshape is that it allows this:
A = 1:12;
B = reshape(A,4,[]);
B =
1 5 9
2 6 10
3 7 11
4 8 12
So if you don't know how many columns there will be, reshape will compute it for you. Likewise, reshape will fill in the number of rows, if you leave that out.
C = reshape(A,[],4)
C =
1 4 7 10
2 5 8 11
3 6 9 12
Try the RESHAPE function:
A = (1-by-12 matrix);
B = reshape(A,4,3);
Note that the matrix B will be filled with elements from A in a columnwise fashion (i.e. columns will be filled from top to bottom, moving left to right).
Example:
>> A = 1:12;
>> B = reshape(A,4,3)
B =
1 5 9
2 6 10
3 7 11
4 8 12
to extend gnovice's solution:
If you need a different order of matrix construction, use transpose (the ' operator) or permute() to change the dimension ordering after you have called reshape().
Related
Let's say we have the following matrix
A=magic(4)
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
and we want to extract 3 submatrices, identified by the indexes for top left and bottom right corners. The indexes for a submatrix are contained in a row of the matrix i; columns 1 and 2 of i are the row indexes of the corners, columns 3 and 4 of i are the column indexes of the corners.
i.e.
i =
1 1 1 3
2 4 1 2
3 4 3 4
>> A(i(1,1):i(1,2),i(1,3):i(1,4))
ans =
16 2 3
>> A(i(2,1):i(2,2),i(2,3):i(2,4))
ans =
5 11
9 7
4 14
>> A(i(3,1):i(3,2),i(3,3):i(3,4))
ans =
6 12
15 1
The command A(i(,):i(,),i(,):i(,)) which I used to extract the submatrices is not very convenient, so I wonder is there a better way to do the job ?
If you don't want to type it all out then why not write a wrapper function?
A = magic(4);
S = #(r) A(i(r,1):i(r,2),i(r,3):i(r,4));
S(1)
S(2)
S(3)
If A may change after the definition of S then you would need to make it a parameter to the function.
S = #(A,r) A(i(r,1):i(r,2),i(r,3):i(r,4));
A = magic(4)
S(A,1)
S(A,2)
S(A,3)
Similarly if i may change then you would need to make it a parameter as well.
Edit
Unfortunately, contrary to my comment, if you want to perform assignment then A(I(r)) won't work exactly the same as what you've posted since this always returns an array instead of a matrix. One possible workaround is to use cell arrays in place of comma-separated-lists, but this isn't as elegant as the read only option. For example
S = #(r) {i(r,1):i(r,2) , i(r,3):i(r,4)};
s = S(1); A(s{:})
s = S(2); A(s{:})
s = S(3); A(s{:})
Following the same principle you could pre-define a cell array from i to make access one line.
s = arrayfun(#(r) {i(r,1):i(r,2),i(r,3):i(r,4)}, 1:size(i,1), 'UniformOutput', false);
A(s{1}{:})
A(s{2}{:})
A(s{3}{:})
I have a 30 x 30 matrix, called A, and I want to assign B as the leftmost 30 x 20 block of A how can I do that?
Is this the correct way to do it?
B = A[30 ; 20]
No the correct way is
B = A(:, 1:20);
where : is shorthand for all of the rows in A.
Matrix indexing in MATLAB uses round brackets, (). Square brackets, [], are used to declare matrices (or vectors) as in
>> v = [1 2 3; 4 5 6; 7 8 9]
v =
1 2 3
4 5 6
7 8 9
excaza provides a very good link on Matrix Indexing in MATLAB which should help you. There is also Matrix Indexing.
A_new = A(:,1:20)
takes all the rows from A with this part A(:,) and the first 20 columns with this part A(,1:20)
A_newis now 30x20
You can also iterate over elements in two loops, but the above answer is easiest
Unfortunately my programming skills are not that advanced and I really need to vectorize some loops to finish my thesis.
I tried to make things really clear and simple and I have the following two questions in matlab:
1.
If we have a 5x5 matrix A and we want to set the diagonal elements of this matrix to the diagonal of a matrix B, apart from diag(A)=diag(B) we could use :
for i=1:5
B(i,i)=A(i,i)
end
Now if I want to vectorize this I can not use:
i=1:5
B(i,i)=A(i,i)
In that way we assign each combination from 1:5. So, in the end we asign each element of A equal to B and not the diagonal.
Is there some way that we could assign each identical pair of (i,i)?
I tried :
i=1:5
j=1:5
B(i,find(j==i))=A(i,find(j==i))
But still does not work. I repeat I know the diag property but Im only interested on the particular problem.
2.
A similar problem is the fillowing.
b=[ones(2,2) ones(2,2)*2 ones(2,2)*3 ones(2,2)*4] ;
a = zeros(8,12);
for i=1:4
a((i-1)*2+1:(i)*2,(i-1)*3+1:(i)*3) = [8*ones(2,1) b(:,[2*(i-1)+1 2*i])];
end
Thank you for your time and for your help.
Let's bring some mask magic, shall we!
Problem #1
mask = eye(size(A))==1
A(mask) = B(mask)
For creating the mask, you can also use bsxfun -
N = size(A,1)
bsxfun(#eq,[1:N]',1:N)
Or finally, you can use linear indexing -
N = size(A,1)
A(1:N+1:N^2) = B(1:N+1:N^2)
Sample run -
>> A
A =
5 2 9 6 5
9 1 6 2 2
9 7 5 3 9
4 5 8 8 7
7 5 8 1 8
>> B
B =
5 5 2 8 2
1 1 6 5 2
7 8 5 4 4
1 8 9 8 8
1 7 6 1 8
>> mask = eye(size(A))==1;
>> A(mask) = B(mask)
A =
5 2 9 6 5
9 1 6 2 2
9 7 5 3 9
4 5 8 8 7
7 5 8 1 8
Problem #2
%// Append 8's at the start of every (2,2) block in b
b1 = reshape([8*ones(2,4) ; reshape(b,4,[])],2,[])
%// Mask where b1 values are to be put in an otherwise zeros filled array
mask = kron(eye(4,4),ones(2,3))==1
%// Initialize output arraya and set values from b1 into masked places
out = zeros(size(mask))
out(mask) = b1
For your first problem. Use logical indexing:
index = diag(ones(1,size(B,1))
B(index) = A(index)
I have a matrix in Matlab, A =
1 2 3
4 5 6
7 8 9
10 11 12
Now I want to create a new matrix B derived from A. The new matrix should look like: B =
1 0
0 4
2 0
0 5
3 0
0 6
Is it possible to solve that without using FOR loop?
Easy with some indexing:
A=[1 2 3 ;
4 5 6 ;
7 8 9 ;
10 11 12 ];
B = zeros(2*size(A,2),2);
B(1:2:end,1)=A(1,:); % put first row values in first column of c
B(2:2:end,2)=A(2,:); % put énd row values in 2nd column of c
If you're only working with 4x4 matrices then yes it is.
You want to convert a 4x4 and using row x column convention you can access A's elements one at at time like so A[row][column]
Then you want a 6x2 matrix then you just call it with zeros B = zeros(6,2)
Then alternate down B[row][column] = A[row][column] and you should be able to build it out easily.
Hi i'm looking for a way to take a slice of an array from the near the end to near the beginning. I know I could do this in two parts, then add them, but it seems like such a commonly desired operation I thought matlab probably already has it built in but I couldn't find any information in my search.
To clarify I would like to be able to say:
y = 1:10
y(-3:3) or y(8:3)
returns:
8 9 10 1 2 3
Thanks in advance.
there actually is a way to do it (without splitting it up in a concatenation of the negative and positive part of indices): use the modulo operator on your desired range:
>> y = 1:10;
>> y(mod([-3:3]-1,numel(y))+1)
ans =
7 8 9 10 1 2 3
This result consists of 7 numbers (opposing your desired [8 9 10 1 2 3]), which is logical because -3:3 actually spans 7 numbers.
The number 0 would correspond to y(end) with this method, -1 would correspond to y(end-1), etc.
You can try this:
y = 1:10;
n = 3;
y([end-n+1:end 1:n]);
This returns
ans =
8 9 10 1 2 3