How can I sort a 2-D array in MATLAB with respect to 2nd row? - sorting

I have array say "a"
a =
1 4 5
6 7 2
if i use function
b=sort(a)
gives ans
b =
1 4 2
6 7 5
but i want ans like
b =
5 1 4
2 6 7
mean 2nd row should be sorted but elements of ist row should remain unchanged and should be correspondent to row 2nd.

sortrows(a',2)'
Pulling this apart:
a = 1 4 5
6 7 2
a' = 1 6
4 7
5 2
sortrows(a',2) = 5 2
1 6
4 7
sortrows(a',2)' = 5 1 4
2 6 7
The key here is sortrows sorts by a specified row, all the others follow its order.

You can use the SORT function on just the second row, then use the index output to sort the whole array:
[junk,sortIndex] = sort(a(2,:));
b = a(:,sortIndex);

How about
a = [1 4 5; 6 7 2]
a =
1 4 5
6 7 2
>> [s,idx] = sort(a(2,:))
s =
2 6 7
idx =
3 1 2
>> b = a(:,idx)
b =
5 1 4
2 6 7
in other words, you use the second argument of sort to get the sort order you want, and then you apply it to the whole thing.

Related

MATLAB: How to re-label a matrix based on another matrix?

Say I have matrix A:
A = [1 1 1 2 2 3 3 3;
1 1 1 2 2 3 3 3;
1 1 1 2 2 4 4 5;
2 2 2 2 2 5 5 5]
and matrix B with the same labels, just in different positions and not always with the same elements in each cluster:
B = [3 3 3 3 5 1 1 1:
3 3 3 3 5 1 1 1;
3 3 3 3 5 2 2 4:
5 5 5 5 5 4 4 4]
and I want matrix C to look like this
C = [1 1 1 1 2 3 3 3;
1 1 1 1 2 3 3 3;
1 1 1 1 2 4 4 5;
2 2 2 2 2 5 5 5]
Basically, I want the clusters in B that have a similar position to A to also have the same label as A, even if the clusters in B don't have the same exact amount of elements as the clusters in A. This is just a basic example because what I'm really working on are two images that have different labellings.
example of the image I'm working on

Matlab: Sum of 2nd column in matrix for equal values in 1st column

i would like to sum all the values from my 2nd column which have the same value in the first column.
So my matrix looks maybe like this:
column: [1 1 1 2 2 3 3 3 3 4 5 5]
column: [3 5 8 2 6 4 0 6 1 0 2 6]
now i would like to have for the value 1 in the 1st column a sum of 3, 5 and 8 in the 2nd column, the same goes for 2, 3 and so from the 1st column.
Like this for example:
[1 2 3 4 5],
[16 8 11 0 8]
i'm thankful for any suggestions!
Sum all values when values are equal :
Just to init :
a = [1 1 1 2 2 3 3 3 3 4 5 5 ; 3 5 8 2 6 4 0 6 1 0 2 6];
a = a.';
Let's go :
n=0
for i=1:size(a,1)
if a(i,1) == a(i,2)
n = n + a(i,1)
end
end
n
For the second question :
mat=0
for j = 1:max(a(:,1))
n=0
for i=1:size(a,1)
if j == a(i,1)
n = n + a(i,2)
end
end
mat(j,1) = j
mat(j,2) = n
end
mat
Result :
mat =
1 16
2 8
3 11
4 0
5 8

Find multiple based on a single criterium (arrayfun)

I am trying to recieve all values from a variable (b) when using a criterium based on another variable (a) (it's like the =IF function in excel). like this:
Example:
(a): 1 2 2 2 3 3 3 3
(b): 3 6 3 5 6 4 5 4
my criteria is
(a) = 2
my reply has to be:
(b) = 6 3 5
I tried to find a solution using arrayfun, like this:
arrayfun(#(x) b(find(a == x, 1, 'first')), 2)
obviously, it only answers the 6, the first number that matches the criterium. Can I somehow formulate arrayfun correctly? Or do I need a whole other function?
Thanks!
Don't you just want:
a = [ 1 2 2 2 3 3 3 3]
b = [3 6 3 5 6 4 5 4]
b(a == 2)
ans =
6 3 5
If a was a matrix then:
a = [ 1 2 2 2 3 3 3 3; ...
1 1 1 2 2 3 4 4; ]
b = [3 6 3 5 6 4 5 4]
b(a(1,:)==2)
ans =
6 3 5

Matlab: removing rows when there are repeated values in columns

I have a problem with removing the rows when the columns are identical.
I have used a for and if loop but the run time is too long.
I was thinking if there are any more efficient and faster run time method.
say
A=[ 2 4 6 8;
3 9 7 9;
4 8 7 6;
8 5 4 6;
2 10 11 2]
I would want the result to be
A=[ 2 4 6 8;
4 8 7 6;
8 5 4 6]
eliminating the 2nd row because of the repeated '9' and remove the 5th row because of repeated '2'.
You can use sort and diff to identify the rows with repeated values
A = A(all(diff(sort(A'))),:)
returns
A =
2 4 6 8
4 8 7 6
8 5 4 6
The trick here is how to find the rows with repeated values in an efficient manner.
How about this:
% compare all-vs-all for each row using `bsxfun`
>> c = bsxfun( #eq, A, permute( A, [1 3 2] ) );
>> c = sum( c, 3 ); % count the number of matches each element has in the row
>> c = any( c > 1, 2 ); % indicates rows with repeated values - an element with more than one match
>> A = A( ~c, : )
A =
2 4 6 8
4 8 7 6
8 5 4 6

Adding zeros between every 2 elements of a matrix in matlab/octave

I am interested in how can I add rows and columns of zeros in a matrix so that it looks like this:
1 0 2 0 3
1 2 3 0 0 0 0 0
2 3 4 => 2 0 3 0 4
5 4 3 0 0 0 0 0
5 0 4 0 3
Actually I am interested in how can I do this efficiently, because walking the matrix and adding zeros takes a lot of time if you work with a big matrix.
Update:
Thank you very much.
Now I'm trying to replace the zeroes with the sum of their neighbors:
1 0 2 0 3 1 3 2 5 3
1 2 3 0 0 0 0 0 3 8 5 12... and so on
2 3 4 => 2 0 3 0 4 =>
5 4 3 0 0 0 0 0
5 0 4 0 3
as you can see i'm considering all the 8 neighbors of an element, but again using for and walking the matrix slows me down quite a bit, is there a faster way ?
Let your little matrix be called m1. Then:
m2 = zeros(5)
m2(1:2:end,1:2:end) = m1(:,:)
Obviously this is hard-wired to your example, I'll leave it to you to generalise.
Here are two ways to do part 2 of the question. The first does the shifts explicitly, and the second uses conv2. The second way should be faster.
M=[1 2 3; 2 3 4 ; 5 4 3];
% this matrix (M expanded) has zeros inserted, but also an extra row and column of zeros
Mex = kron(M,[1 0 ; 0 0 ]);
% The sum matrix is built from shifts of the original matrix
Msum = Mex + circshift(Mex,[1 0]) + ...
circshift(Mex,[-1 0]) +...
circshift(Mex,[0 -1]) + ...
circshift(Mex,[0 1]) + ...
circshift(Mex,[1 1]) + ...
circshift(Mex,[-1 1]) + ...
circshift(Mex,[1 -1]) + ...
circshift(Mex,[-1 -1]);
% trim the extra line
Msum = Msum(1:end-1,1:end-1)
% another version, a bit more fancy:
MexTrimmed = Mex(1:end-1,1:end-1);
MsumV2 = conv2(MexTrimmed,ones(3),'same')
Output:
Msum =
1 3 2 5 3
3 8 5 12 7
2 5 3 7 4
7 14 7 14 7
5 9 4 7 3
MsumV2 =
1 3 2 5 3
3 8 5 12 7
2 5 3 7 4
7 14 7 14 7
5 9 4 7 3

Resources