Sort a partition of an array in MATLAB - arrays

I have the following cell array A of size 1x9
A= {{'O1'} ,{'O1','O2','O3','O4'} ,{'O1','O3'} ,{'O1','O2','O3','O4'} , {},{'O1','O2','O3','O4'},{'O1','O3'},{'O1','O2','O3','O4'},{'O1','O2','O3','O4'}};
I want to sort a partition of this cell array starting the fifth element A{5:9} according to number of elements in the cell . I have tried the sort function as follows by didn't seems to work
[P,I] = sort(cellfun('length',A{5:9}));
A = A(I);
Also is there any way to keep track of the original indices of the cellarray after sorting ?

The sorting can be performed with the following code/
A= {{'O1'} ,{'O1','O2','O3','O4'} ,{'O1','O3'} ,{'O1','O2','O3','O4'} , {},
{'O1','O2','O3','O4'},{'O1','O3'},{'O1','O2','O3','O4'},{'O1','O2','O3','O4'}};
disp('Before sorting')
for ii = 1:numel(A)
fprintf('%d: %s\n',ii, cell2str(A{ii}));
end
a=A(5:end);
[P,I] = sort( cellfun(#(x) numel(x),a) );
A(5:end) = a(I);
clear a
disp('After sorting')
for ii = 1:numel(A)
fprintf('%d: %s\n',ii, cell2str(A{ii}));
end
The mapping between the initial and final order of the cell array can be found using again I:
originalOrder = 1:numel(A);
finalOrder = originalOrder;
o = originalOrder(5:end);
finalOrder(5:end) = o(I);
clear o
In your case: finalOrder = [1 2 3 4 5 7 6 8 9]
The original position of cell 6in the modified A was finalOrder(6) = 7.

Related

How can I find the nonzero values in a MATLAB cells array?

The following code generates an cell array Index [1x29], where each cell is an array [29x6]:
for i = 1 : size(P1_cell,1)
for j = 1 : size(P1_cell,2)
[Lia,Lib] = ismember(P1_cell{i,j},PATTERNS_FOR_ERANOS_cell{1},'rows');
Index1(i,j) = Lib % 29x6
end
Index{i} = Index1; % 1x29
end
How can I find the nonzero values in Index array?, i.e. generate an array with the number of non-zero values in each row of the Index1 array. I tried the following loop, but it doesn't work, it creates conflict with the previous one:
for i = 1 : length(Index)
for j = 1 : length(Index)
Non_ceros = length(find(Index{:,i}(j,:))); %% I just need the length of the find function output
end
end
I need help, Thanks in advance.
The nnz() (number of non-zeros) function can be used to evaluate the number of non-zero elements. To obtain the specific positive values you can index the array by using the indices returned by the find() function. I used some random test data but it should work for 29 by 6 sized arrays as well.
%Random test data%
Index{1} = [5 2 3 0 zeros(1,25)];
Index{2} = [9 2 3 1 zeros(1,25)];
Index{3} = [5 5 5 5 zeros(1,25)];
%Initializing and array to count the number of zeroes%
Non_Zero_Counts = zeros(length(Index),1);
for Row_Index = 1: length(Index)
%Evaluating the number of positive values%
Array = Index{Row_Index};
Non_Zero_Counts(Row_Index) = nnz(Array);
%Retrieving the positive values%
Positive_Indices = find(Array);
PositiveElements{Row_Index} = Array(Positive_Indices);
disp(Non_Zero_Counts(Row_Index) + " Non-Zero Elements ");
disp(PositiveElements{Row_Index});
end
Ran using MATLAB R2019b
for i = 1 : length(Index)
for j = 1 : length(Index)
Non_ceros(i,j) = nnz(Index{:,i}(j,:));
end
end

Sort array elements by the frequency of its elements

Is it possible in matlab/octave to use the sort function to sort an array based on the relative frequency of their elements?
For example the array
m= [4,4,4,10,10,10,4,4,5]
should result in this array:
[5,10,10,10,4,4,4,4,4]
5 is the less frequent element and is on the top while 4 is the most frequent and it's on bottom.
Should one use the indices provided by histcount?
The following code first calculates how often each element occurs and then uses runLengthDecode to expand the unique elements.
m = [4,4,4,10,10,10,4,4,5];
u_m = unique(m);
elem_count = histc(m,u_m);
[elem_count, idx] = sort(elem_count);
m_sorted = runLengthDecode(elem_count, u_m(idx));
The definition of runLengthDecode is copied from this answer:
For MATLAB R2015a+:
function V = runLengthDecode(runLengths, values)
if nargin<2
values = 1:numel(runLengths);
end
V = repelem(values, runLengths);
end
For versions before R2015a:
function V = runLengthDecode(runLengths, values)
%// Actual computation using column vectors
V = cumsum(accumarray(cumsum([1; runLengths(:)]), 1));
V = V(1:end-1);
%// In case of second argument
if nargin>1
V = reshape(values(V),[],1);
end
%// If original was a row vector, transpose
if size(runLengths,2)>1
V = V.'; %'
end
end
One way would be to use accumarray to find the count of each number (I suspect you can use histcounts(m,max(m))) but then you have to clear all the 0s).
m = [4,4,4,10,10,10,4,4,5];
[~,~,subs]=unique(m);
freq = accumarray(subs,subs,[],#numel);
[~,i2] = sort(freq(subs),'descend');
m(i2)
By combinging my approach with that of m.s. you can get a simpler solution:
m = [4,4,4,10,10,10,4,4,5];
[U,~,i1]=unique(m);
freq= histc(m,U);
[~,i2] = sort(freq(i1),'descend');
m(i2)
You could count the number of repetitions with bsxfun, sort that, and apply that sorting to m:
[~, ind] = sort(sum(bsxfun(#eq,m,m.')));
result = m(ind);

Finding same value in rows & columns of a 2D array

Hi guys I want to solve sodoku puzzles in matlab. My problem is that I should find same value in every row and every column and every 3*3 sub array.
Our 2d array is 9*9 and populated with value 1-9 randomly.
I wrote this for finding same value in rows, but I don't know how I should do it for columns and 3*3 sub arrays.
conflict_row = 0;
for i=1:9
temp = 0;
for j=1:9
if (temp==A(i,j))
conflict_row = conflict_row+1;
end
temp = A(i,j);
end
end
Sorry I'm a newbie.
Find values that are present in all columns:
v = find(all(any(bsxfun(#eq, A, permute(1:size(A,1), [3 1 2])),1),2));
Find values that are present in all rows:
v = find(all(any(bsxfun(#eq, A, permute(1:size(A,2), [3 1 2])),2),1));
Find values that are present in all 3x3 blocks: reshape the matrix as in this answer by A. Donda to transform each block into a 3D-slice; then reshape each block into a column; and apply 1:
m = 3; %// columns per block
n = 3; %// rows per block
B = permute(reshape(permute(reshape(A, size(A, 1), n, []), [2 1 3]), n, m, []), [2 1 3]);
B = reshape(B,m*n,[]);
v = find(all(any(bsxfun(#eq, B, permute(1:size(B,1), [3 1 2])),1),2));
Probably not the fastest solution but why don't you make a function of it and use it once for rows and once for columns
[conflict_row ] = get_conflict(A)
for i=1:9
temp = 0;
for j=1:9
if (temp==A(i,j))
conflict_row = conflict_row+1;
end
temp = A(i,j);
end
end
And then you call it twice
conflict_row = get_conflict(A); % Rows
Transpose A to get the columns
Convert the columns to rows and use the same code as before
conflict_col = get_conflict(A.');
If you want to work within the same column then you should do something like this (also sorry this is in C# I don't know what language you are working in):
int currentCol = 0;
foreach (var item in myMultiArray)
{
int currentColValue = item[currentCol];
}
This works because myArray is a array of arrays thus to select a specific column can easily be picked out by just allowing the foreach to perform your row iteration, and you just have to select the column you need with the currentCol value.

How to convert a character matrix into cell array?

I have 64 characters in a 4*4 matrix.I need to convert it into a cell array such that cell has 4 characters.For eg
Consider A=[TCTGCTCTCGGTTATATACACTGCCCAGAACACGTCAACAAGGCCAGTGTATCCTTCTTTGTGT]
i need to get a cell array as below
B={[TCTG][CTCT][CGGT][TATA]
[TACA][CTGC][CCAG][AACA]
[CGTC][AACA][AGGC][CAGT]
[GTAT][CCTT][CTTT][GTGT]}
i tried using the mat2cell function but im not able to understand it.please help.
Using a for-loop:
clc
clear
A = 'TCTGCTCTCGGTTATATACACTGCCCAGAACACGTCAACAAGGCCAGTGTATCCTTCTTTGTGT';
B = cell(4,4);
currentIdx = 0; % Use index to increment by steps of 4 when going through A
for k = 1:16
B{k} = A(currentIdx+1:currentIdx+4);
currentIdx = currentIdx+4;
end
B = B'
B =
'TCTG' 'CTCT' 'CGGT' 'TATA'
'TACA' 'CTGC' 'CCAG' 'AACA'
'CGTC' 'AACA' 'AGGC' 'CAGT'
'GTAT' 'CCTT' 'CTTT' 'GTGT'
You are starting with a 1xN matrix and want to convert it to a 1xN/4 cell array of 1x4 matrices. Your command should then be:
N = length(A);
M = 4;
B = mat2cell(A,1,ones(1,N/M)*M);
The first dimension is the 1, the second dimension is a string of 4's the size of the output cell array. The result:
B =
Columns 1 through 12
'TCTG' 'CTCT' 'CGGT' 'TATA' 'TACA' 'CTGC' 'CCAG' 'AACA' 'CGTC' 'AACA' 'AGGC' 'CAGT'
Columns 13 through 16
'GTAT' 'CCTT' 'CTTT' 'GTGT'
You can use method vec2mat that breaks your input vector to matrix
M = vec2mat(A, numberOfColumns)
(In your case numberOfColumns would be 16) and then use mat2cell. In your case, it would be:
C = mat2cell(M, [1,1,1,1], [4,4,4,4])
It means that all cels will have one row and 4 columns).
Effect of function c = mat2cell(x, [10, 20, 30], [25, 25]) would be:
The image shows why you have to convert vector to matrix. (example from matlab documentation)
You can also (ab)use the very versatile accumarray for this task:
A = 'TCTGCTCTCGGTTATATACACTGCCCAGAACACGTCAACAAGGCCAGTGTATCCTTCTTTGTGT';
n = 4;
B = accumarray(ceil(1/n:1/n:numel(A)/n).', A(:), [], #(x) {x.'}).'

reshape 2d array to 3d array in matlab /octave

How can I reshape a 2d array to a 3d array with the last column being used as pages?
All data found in array2d should be in pages
example:
array2d=[7,.5,12; ...
1,1,1; ...
1,1,1; ...
4,2,4; ...
2,2,2; ...
2,2,2; ...
3,3,3; ...
3,3,3; ...
3,3,3];
The first page in the array would be
7,.5,12;
1,1,1;
1,1,1;
The second page in the array would be
4,2,4;
2,2,2;
2,2,2;
The third page in the array would be
3,3,3;
3,3,3;
3,3,3;
This is a 9x3 array how can I get it to be a 9x3x? (not sure what this number should be so I placed a question mark as a place holder) multidimensional array?
What I'm trying to get is to have
All the ones would be on one dimension/page all the two's would be another dimension/page etc... –
I tried reshape(array2d,[9,3,1]) and it's still a 9x3
Use permute with reshape -
N = 3; %// Cut after every N rows to form a "new page"
array3d = permute(reshape(array2d,N,size(array2d,1)/N,[]),[1 3 2]) %// output
Assuming that each slice of your matrix is the same in dimensions, we can do this very easily. Let's call the number of rows and columns that each slice would have to be M and N respectively. In your example, this would be M = 3 and N = 3. As such, assuming array2d is of the above form, we can do the following:
M = 3;
N = 3; %// This is also simply the total number of columns we have,
%// so you can do size(array2d, 2);
outMatrix = []; %// Make this empty. We will populate as we go.
%// Figure out how many slices we need
numRows = size(array2d,1) / M;
for k = 1 : numRows
%// Extract the k'th slice
%// Reshape so that it has the proper dimensions
%// of one slice
sliceK = reshape(array2d(array2d == k), M, N);
%// Concatenate in the third dimension
outMatrix = cat(3,outMatrix,sliceK);
end
With your example, we thus get:
>> outMatrix
outMatrix(:,:,1) =
1 1 1
1 1 1
1 1 1
outMatrix(:,:,2) =
2 2 2
2 2 2
2 2 2
outMatrix(:,:,3) =
3 3 3
3 3 3
3 3 3
This method should generalize for any number of rows and columns for each slice, provided that each slice shares the same dimensions.
Your array is already of size 1 in the 3rd dimension (in other words, it is already 9x3x1, to prove this try entering array2d(1,1,1)). If you want to concatenate 2d matrices along the 3rd dimension you can use cat.
For example:
a = [1,2;3,4];
b = [5,6;7,8];
c = cat(3,a,b);
c will be a 2x2x2 matrix.
This piece of code is specific for this example, I hope you will be able to understand how to go for other data samples.
out2 = [];
col = size(array2d,2);
for i = 1:3
temp2 = reshape(array2d(array2d == i),[],col);
out2 = cat(3,out2,temp2);
end

Resources