MATLAB: Finding n-th smallest element in per row - matlab

I want to find the n-th smallest element for each row in a matrix.
Example:
n = 2
M = [1, 2, 3; 4, 5, 6; 7, 8 9]
Result = [2, 5, 8]

First sort the matrix by the second dimension (i.e. sort every row in ascending order):
n = 2
M = [1, 2, 3; 4, 5, 6; 7, 8 9]
M_SORTED = sort(M,2)
M_SORTED =
1 2 3
4 5 6
7 8 9
The n-th column of the matrix will contain the result:
RESULT = M_SORTED(:, n)
RESULT =
2
5
8

Related

Minimum of two multidimensional matrices, with which matrix 'won' (contained the minimum)

I have two matrices (size 4x4) and I want to find the minimum between the two. For example:
A = [ 3, 2, 4, 5;
1, 2, 0, 6;
9, 8, 5, 4;
0, 1, 0, 3 ];
B = [ 1, 1, 6, 8;
0, 4, 6, 3;
5, 6, 7, 1;
0, 2, 3, 4 ];
Now, if I did a min(A,B) in Octave, it gives me
[ 1, 1, 4, 5;
0, 2, 0, 3;
5, 6, 5, 1;
0, 1, 0, 3 ]
Is there a way to get the matrix that 'won', by which I mean which matrix contained the minimum, in each element-wise comparison?
Like, for the first element of both matrices, matrix B won and so on.
I don't want to loop through the matrices.
You can compare A and B to find out in which matrix the minimum occurred.
With A > B, you will get a matrix containing False if the entry from A was chosen, and True if the entry from B was chosen. By adding 1 to it, you will get 1 if A was chosen and 2 if B was chosen.
>> 1 + (A > B)
ans =
2 2 1 1
2 1 1 2
2 2 1 2
1 1 1 1
Alternatively, you can concatenate A and B to form a 3-dimensional array with dimensions [4, 4, 2], where C(:, :, 1) = A and where C(:, :, 2) = B. Then you can call min on this matrix C along the third axis. When calling min on one matrix, you can get the index of the "winner" directly as a second return value:
>> C = cat(3, A, B);
>> [res, idx] = min(C, [], 3)
res =
1 1 4 5
0 2 0 3
5 6 5 1
0 1 0 3
idx =
2 2 1 1
2 1 1 2
2 2 1 2
1 1 1 1

Convert a matrix to a vector using a spiral path

I have seen until now that when someone wants to read the elements of a matrix using a spiral one by one they always mean starting outwards and slowly moving to the center using an MxM matrix. How would we do the opposite, start from a random point inside the matrix and using a "spiraling" path to read all the elements.
I am doing the tests using Matlab.
Example.
mat=
1 2 3
4 5 6
7 8 9
If lets say we were to start from mat(3,1) spiraling clockwise then we would have
vec=
7, 8, 4, 5, 6, 9, 1, 2, 3
and if we started from mat(2,2) then
vec=
5, 6, 9, 8, 7, 4, 1, 2, 3
One possible approach:
mat = [1 2 3; 4 5 6; 7 8 9];
M = length(mat); % Assuming mat is always MxM
r = 3;
c = 1;
temp = spiral(2 * M - 1);
temp = temp(M - r + 1:end - r + 1, M - c + 1:end - c + 1);
[~, idx] = sort(temp(:));
vec = mat(idx).'
Result running with r = 3 and c = 1
vec =
7 8 4 5 6 9 1 2 3
Result running with r = 2 and c = 2
vec =
5 6 9 8 7 4 1 2 3

Concatenate two arrays in MATLAB

I have a 5000x2 array as:
A = [1, 3; 2, 4; 1, 6; 2, 4; 1, 7];
I have another array of size 100x2 which looks as:
B = [1, 14; 2, 15];
How can I create a third array where I am going to use column 2 of vector B as follows to modify matrix A:
C = [1, 3, 14; 2, 4, 15; 1, 6, 14; 2, 4, 15; 1, 7, 14];
I am just trying to use column 1 of B as keys which would be same as contents of column 1 of A.
Assuming the first column on B is indices = 1 2 3 4 ..., the following should work:
A =
1 3
2 4
2 6
2 4
1 7
2 8
C(:,3) = B(A(:,1),2)
C =
1 3 14
2 4 15
2 6 15
2 4 15
1 7 14
2 8 15
or if you just want 14 15 14 15:
C = [A repmat(B(:,2),size(A,1)/size(B,1),1)]
Do the following:
A(A(:,1)== key ,3) = B(B(:,1)== key ,2);
where key takes the values of 1 and 2 (and any other possible key).
What does this line do? A(:,1)== key will be true on the rows where the first column values are equal to key, and then sets the third column of A equal to the values of B that have the same key.
You should execute this line for key=1 and key=2 in order to get what you need.

MatLab - histc with many edges vector

Consider this :
a = [1 ; 7 ; 13];
edges = [1, 3, 6, 9, 12, 15];
[~, bins] = histc(a, edges)
bins =
1
3
5
Now I would like to have the same output, but with a different "edges" vector for each a value, i.e. a matrix instead of a vector for edges. Exemple :
a = [1 ; 7 ; 13];
edges = [ 1, 3, 6 ; 1, 4, 15 ; 1, 20, 30];
edges =
1 3 6
1 4 15
1 20 30
indexes = theFunctionINeed(a, edges);
indexes =
1 % 1 inside [1, 3, 6]
2 % 7 indide [1, 4, 15]
1 %13 inside [1, 20, 30]
I could do this with histc inside a for loop, by I'm trying to avoid loops.
If you transform your arrays to cell arrays, you can try
a = {1 ; 7 ; 13};
edges = {[ 1, 3, 6 ];[ 1, 4, 15] ; [1, 20, 30]};
[~, indexes] = cellfun(#histc, a, edges,'uniformoutput', false)
This results in
indexes =
[1]
[2]
[1]
~edit~
To transform your matrices into cell arrays you can use num2cell:
a = num2cell(a);
edges = num2cell(edges, 2);
You could also do:
a = [1; 7; 13];
edges = [1 3 6; 1 4 15; 1 20 30];
bins = sum(bsxfun(#ge, a, edges), 2)
The result:
>> bins
bins =
1
2
1

matlab - cellfun sum all elements of each cell

Hi I have populated a cell array using:
D(i) = {dist};
D = reshape(D, w, h)
so that if i have:
pix1 = D{1,1};
pix2 = D{2,2};
I get
pix1 =
1 2 3
pix2 =
4 5 6
What I want to do is sum all the elements in each pix, and then take those results and form a matrix i.e.
sum(pix1) = 6
sum(pix2) = 15
matrix =
6 15
where in this case matrix is a 1X2 matrix (mine is a lot larger).
I am trying to do this using:
field = cellfun(#(dist) sum(dist(:)), D,'UniformOutput', false);
but this just gives me a matrix full of NaN's. Where am I going wrong?
A = {[1 2 4], [4 5 6]};
B = cellfun(#sum, A)
results in
B = [6 15]
B = [7 15]
In case you have NaNs in your cells and you wish to ignore them you may use nansum:
A = {[1, 2, NaN], [3, NaN, 4, 5]; [6, NaN], [10, -3, NaN, 4]};
B = cellfun( #nansum, A )
Results with
B =
3 12
6 11