Suppose I have a matrix in MATLAB.
>> m = [1 2 3; 4 5 6; 7 8 9]
m =
1 2 3
4 5 6
7 8 9
I have a list of indices, and I would like elements at those indices to be removed from the matrix.
The indices may belong to any arbitrary row or column. However, I can guarantee that if I were to remove an element from a row, I must remove an element from all other rows.
Once all the elements are removed, any "gaps" in the matrix should be addressed by shifting elements to the left.
% for example, removing m(1, 1), m(2, 2), m(3, 3) should yield
m =
2 3
4 6
7 8
% it will NOT yield the following because the elements were shifted up, not to the left.
M =
4 2 3
7 8 6
% removing only m(1, 1) would also be invalid,
% because I must remove an element from all other rows.
What would be the most efficient way to perform this operation for arbitrary number of indices?
As you need the elements shifted up, the solution is a two-step one. First transpose the matrix, remove the corresponding elements, and then reshape and transpose the result. (If shifting up were allowed, then you wouldn't need to transpose). Assuming the indices are stored in a matrix, remove, then:
m=[1,2,3;4,5,6;7,8,9];
remove=[1,1;2,2;3,3];
copy=m.';
width=size(copy,2);
copy(sub2ind(size(copy),remove(:,2),remove(:,1)))=[];
m=reshape(copy,[],width).'
I think that solves the problem...
Related
I have a matrix where each element is a single unit of a 2d coordinate. As such, each element in any given row are paired, where elements in the first column are paired with those in the second, and elements in the third column paired with the fourth. All possible combinations of the 4 numbers are present in the matrix.
What I need to do is depup the matrix by removing rows where the first set of coordinates (e.g columns 1 and 2 in a row) are swapped with the second set of coordinates. For example if one row contains the value "3, 4, 2, 1" then I would need to remove "2, 1, 3, 4" from else where in the matrix.
An example of this could be seen below, where I would want to remove the last row, as it is the reverse of the first row;
3 3 1 1
1 2 2 3
3 4 1 2
4 4 3 1
4 1 4 4
1 1 3 3
I'm quite stumped as to how to do this, and my previous attempts have all failed. Whilst it may not be useful to the answer, I have included my code showing how I am constructing the initial matrix below;
%create list of all piece coordinates
p1_row_index=(1:n);
p1_column_index=(1:n);
p2_row_index=(1:n);
p2_column_index=(1:n);
% get all possible combinations of these variables
[p1_row_index,p1_column_index,p2_row_index,p2_column_index]=BalanceFactors(1,1,1:n,1:n,1:n,1:n);
pc_list(:,1)=p1_row_index; % piece1 coordiantes for rows
pc_list(:,2)=p1_column_index; % piece1 coordiantes for columns
pc_list(:,3)=p2_row_index; % piece2 coordiantes for rows
pc_list(:,4)=p2_column_index; % piece2 coordiantes for columns
Thank you for your time.
Many thanks,
Matt
Complex numbers come in handy for this:
[~, ind] = unique(sort(M(:,[1 3])+1j*M(:,[2 4]), 2), 'rows', 'stable');
result = M(ind, :);
The code works as follows:
M(:,[1 3])+1j*M(:,[2 4]) creates a complex matrix with half the columns, where each pair of coordinates of the original matrix becomes a complex number.
sort(..., 2) sorts each row. Rows that originally were shuffled versions of each other now become identical.
[~, ind] = unique(..., 'rows', 'stable') gives the index of the first occurrence of each unique (complex, sorted) row.
M(ind, :) selects the desired rows from M.
I would like to create a column vector from the elements of a matrix A of size (3,3) that are not on the diagonal. Thus, I would have 6 elements in that output vector. How can I do this?
Use eye and logical negation, although this is no better than Divakar's original answer, and possibly significantly slower for very large matrices.
>> A = magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
>> A(~eye(size(A)))
ans =
5
9
4
2
7
14
3
10
15
13
8
12
Use this to get such a column vector, assuming A is the input matrix -
column_vector = A(eye(size(A))==0)
If you don't care about the order of the elements in the output, you can also use a combination of setdiff and diag -
column_vector = setdiff(A,diag(A))
You can also use linear indexing to access the diagonal elements and null them. This will automatically reshape itself to a single vector:
A(1:size(A,1)+1:end) = [];
Bear in mind that this will mutate the original matrix A. If you don't want this to happen, make a copy of your matrix then perform the above operation on that copy. In other words:
Acopy = A;
Acopy(1:size(A,1)+1:end) = [];
Acopy will contain the final result. You need to create a vector starting from 1 and going to the end in increments of the rows of the matrix A added with 1 due to the fact that linear indices are column-major, so the linear indices used to access a matrix progress down each row first for a particular column. size(A,1) will allow us to offset by each column and we add 1 each time to ensure we get the diagonal coefficient for each column in the matrix.
Assuming that the matrix is square,
v = A(mod(0:numel(A)-1, size(A,1)+1) > 0).';
In MATLAB I have a very large matrix (matrix A). Now I would like to find the row-index of the row which contain certain values in the second column. These values - which I'm looking for in Matrix A - are stored in anonther Matrix (Matrix B) with consists out of a row (800 numbers).
Besides I would like to redo this calculation for the same matrix A, but for ten different matrices, with different sizes (which contain the values I'm looking for in different columns of matrix A).
Because of the sizes of the matrix I think i need a loop to extract the row in matrix A which contain te value of Matrix B. How can I do this?
regards,
V
Thanks for the quick response! Indeed the problem is maybe a bit complex to answer without an example, and indeed duplicate entries cause some problems. Therefore hereby an example
For example I have a -simplified- matrix A:
1 2 3 4
9 9 9 9
4 3 2 1
And a -simplified- matrix (row) B: [9 3]
And a -simplified- matrix (row) C: [9 2]
Then I would like to get matrix D and matrix E.These matrices should contain in the first column the numbers from the original matrix D(or E) and in the second column the corresponding row-location of this value in matrix A.
So, matrix D =
9 2
3 3
matrix E =
9 2
2 3
As represented in this example matrix B and matrix C can contain data which is present in several column of matrix A (like the nine). However, martix B should "search" in column 2 of matrix A. Likewise, should matrix C "search" in column 3 of Matrix A, resulting in matrix D and E as given in the example.
As mentionned by Shai in his comment, your question is quite vague and a lot of special case could arise (duplicate entries, relative size of A and B, etc.). But in all generality I tried a small piece of code that seems to do what you want. There are certainly quicker ways of doing it, and certainly more information on your problem could help optimize this.
colA=2;
% Example
nmax=10;
nA=5;
A=randi(nmax,[nA nA]);
nB=3;
B=randi(nmax,[1 nB]);
% Find rows
rows=cell(size(B));
for i=1:numel(B)
rows(i)={find(A(:,colA)==B(i))};
end
The input / output was:
A =
3 7 8 5 4
9 7 3 7 5
8 2 9 9 8
9 5 9 7 9
3 3 4 6 8
B =
1 7 5
rows =
[0x1 double] [1;2] [4]
Assuming you have two vectors, largeDataIndex (the second column of your matrix) and interestingIndex (your b) and you want the following:
For each value of interestingIndex , find the position in largeDataIndex
Then an easy method would be this:
result = zeros(size(interestingIndex))
for i = 1:length(result)
result(i) = find(interestingIndex(i) == largeDataIndex)
end
Note that this assumes there is always just one entry that matches, otherwise you should define result as a cell array rather than a vector.
I would like to average every 3 values of an vector in Matlab, and then assign the average to the elements that produced it.
Examples:
x=[1:12];
y=%The averaging operation;
After the operation,
y=
[2 2 2 5 5 5 8 8 8 11 11 11]
Therefore the produced vector is the same size, and the jumping average every 3 values replaces the values that were used to produce the average (i.e. 1 2 3 are replaced by the average of the three values, 2 2 2). Is there a way of doing this without a loop?
I hope that makes sense.
Thanks.
I would go this way:
Reshape the vector so that it is a 3×x matrix:
x=[1:12];
xx=reshape(x,3,[]);
% xx is now [1 4 7 10; 2 5 8 11; 3 6 9 12]
after that
yy = sum(xx,1)./size(xx,1)
and now
y = reshape(repmat(yy, size(xx,1),1),1,[])
produces exactly your wanted result.
Your parameter 3, denoting the number of values, is only used at one place and can easily be modified if needed.
You may find the mean of each trio using:
x = 1:12;
m = mean(reshape(x, 3, []));
To duplicate the mean and reshape to match the original vector size, use:
y = m(ones(3,1), :) % duplicates row vector 3 times
y = y(:)'; % vector representation of array using linear indices
The following example appears in the MATLAB tutorial:
X = [16 2 13;
5 11 8;
9 7 12;
4 14 1]
Using a single subscript deletes a single element, or sequence of elements, and reshapes the remaining elements into a row vector. So:
X(2:2:10) = []
results in:
X = [16 9 2 7 13 12 1]
Mysteriously, the entire 2nd row and the first two elements in the 4th row have been deleted, but I can't see the correspondence between the position of the deleted elements and the index vector 2:2:10. Can someone please explain?
The example you gave shows linear indexing. When you have a multidimensional array and you give it a single scalar or vector, it indexes along each column from top to bottom and left to right. Here's an example of indexing into each dimension:
mat = [1 4 7; ...
2 5 8; ...
3 6 9];
submat = mat(1:2, 1:2);
submat will contain the top left corner of the matrix: [1 4; 2 5]. This is because the first 1:2 in the subindex accesses the first dimension (rows) and the second 1:2 accesses the second dimension (columns), extracting a 2-by-2 square. If you don't supply an index for each dimension, separated by commas, but instead just one index, MATLAB will index into the matrix as though it were one big column vector:
submat = mat(3, 3); % "Normal" indexing: extracts element "9"
submat = mat(9); % Linear indexing: also extracts element "9"
submat = mat([1 5 6]); % Extracts elements "1", "5", and "6"
See the MATLAB documentation for more detail.
It's very simple.
It basically starts from the second element in this example and goes upto tenth element (column wise) in steps of 2 and deletes corresponding elements. The remaining elements result in a row vector.