Reputation: 107
How do I sort a column based on the values in another column in MATLAB?
Column A
shows position data (it is neither ascending or descending in order) Column B
contains another column of position data. Finally column C
contains numerical values. Is it possible to link the first position value in B
with its numerical value in the first cell of C
? Then after this I want to sort B
such that it is in the same order as column A
with the C
values following their B
counterparts?The length of my columns would be 1558 values.
Before case;
A B C
1 4 10
4 1 20
3 5 30
5 2 40
2 3 50
After Case;
A B C
1 1 20
4 4 10
3 3 50
5 5 30
2 2 40
Basically A
and B
became the same and Column C
followed B
.
Upvotes: 1
Views: 407
Reputation: 16791
Given M = [A B C]
:
M =
1 4 10
4 1 20
3 5 30
5 2 40
2 3 50
You need to sort the rows of the matrix excluding the first column:
s = sortrows(M(:,2:3));
s =
1 20
2 40
3 50
4 10
5 30
Then use the first column as the indices to reorder the resulting submatrix:
s(M(:,1),:);
ans =
1 20
4 10
3 50
5 30
2 40
This would be used to build the output matrix:
N = [M(:,1) s(M(:,1),:)];
N =
1 1 20
4 4 10
3 3 50
5 5 30
2 2 40
The previous technique will obviously only work if A
and B
are permutations of the values (1..m)
. If this is not the case, then we need to find the ranking of each value in the array. Let's start with new values for our arrays:
A B C
1 5 60
6 1 80
9 6 60
-4 9 40
5 -4 30
We construct s
as before:
s = sortrows([B C]);
s =
-4 30
1 80
5 60
6 60
9 40
We can generate the rankings one of two ways. If the elements of A
(and B
) are unique, we can use the third output of unique
as in this answer:
[~, ~, r] = unique(A);
r =
2
4
5
1
3
If the values of A
are not unique, we can use the second return value of sort, the indices in the original array of the elements in sorted order, to generate the rank of each element:
[~, r] = sort(A);
r =
4
1
5
2
3
[~, r] = sort(r);
r =
2
4
5
1
3
As you can see, the resulting r
is the same, it just takes 2 calls to sort
rather than 1 to unique
. We then use r
as the list of indices for s
above:
M = [A s(r, :)];
M =
1 1 80
6 6 60
9 9 40
-4 -4 30
5 5 60
Upvotes: 1
Reputation: 1212
Since you don't want things necessarily in ascending or descending order, I don't think any built-in sorting functions like sortrows()
will help here. Instead you are matching elements in one column with elements in another column.
Using [~,idx]=ismember(A,B)
will tell you where each element of B is in A. You can use that to sort the desired columns.
M=[1 4 10
4 1 20
3 5 30
5 2 40
2 3 50];
A=M(:,1); B=M(:,2); C=M(:,3);
[~,idx]=ismember(A,B);
sorted_matrix = [A B(idx) C(idx)]
Upvotes: 6
Reputation: 221504
Powerful combo of bsxfun
and matrix-multiplication
solves it and good for code-golfing
too! Here's the implementation, assuming M
as the input matrix -
[M(:,1) bsxfun(@eq,M(:,1),M(:,2).')*M(:,2:3)]
Sample run -
>> M
M =
1 4 10
4 1 20
3 5 30
5 2 40
2 3 50
>> [M(:,1) bsxfun(@eq,M(:,1),M(:,2).')*M(:,2:3)]
ans =
1 1 20
4 4 10
3 3 50
5 5 30
2 2 40
Upvotes: 1
Reputation: 2802
If you must retain the order of A
then use something like this
matrix = [1 4 10; 4 1 20; 3 5 30; 5 2 40; 2 3 50];
idx = arrayfun(@(x) find(matrix(:,2) == x), matrix(:,1));
sorted = [matrix(:,1), matrix(idx,2:3)];
Upvotes: 0