MatLab find cells with specific values in two cell arrays - arrays

I want to find cells, which are at the same position in two different cell arrays and which have specific values.
The two cell arrays have the following structure:
cell array C1= cell(20,1). In each cell there is another cell cell(8129,8) holding double values in the range of [0,1].
Cell array C2= cell(20,1). In each cell there is another cell cell(8192,8) also holding double values in the range of [0,1].
I know want to find those cells, which (1) have a specific value that I determine (e.g. C1_value = 0.8 and C2_value = 0.85) and (2) are at the same position in the respective sub cell (!) array (e.g. C1{2}(736) == 0.8 and C2(19)(736) == 0.85). NOTE: The same position only refers to the subcell arrays (cell(8192,8)) not the "main" cell arrays C1(:) and C2(:)
Thanks in advance!

See if this approach works for you -
sz = cell2mat(cellfun(#size,C1(1),'uni',0))
row1 = sz(1);
col1 = sz(2);
t1 = reshape(horzcat(C1{:}),row1,col1,[])
t2 = reshape(horzcat(C2{:}),row1,col1,[])
b1 = t1==C1_value
b2 = t2==C2_value
tt1 = reshape(b1,row1*col1,[])' %//'
tt2 = reshape(b2,row1*col1,[])' %//'
tt22 = permute(tt2,[3 2 1])
tt3 = bsxfun(#and,tt1,tt22)
[C1_cellnum,subcellnum,C2_cellnum] = ind2sub(size(tt3),find(tt3)) %// outputs
Thus, with your sample data, you must have -
C1_cellnum as 2, C2_cellnum as 19 and subcellnum as 736.

Related

How to convert matrix to cell array

I have matrix A = 50x2
How to convert the data into cell array.
Should be I have 10 cell which each cell contain data [5x2].
Thank you for help.
That is what mat2cell does:
A = rand(50,2); % example matrix
N = 10; % number of cells in which to split the first dimension
result = mat2cell(A, repmat(size(A,1)/N, 1, N), size(A,2));
One can use num2cell:
N_ROWS = 5; N_COLS = 2;
A = rand(50,2);
B = num2cell(reshape(A,N_ROWS,N_COLS,[]),[1,2]); % B is 1x1x10 cell array
What this does is turn your input array into 5x2 "slices" stacked along the 3rd dimension.
You can add a squeeze(B), B = B(:) or a reshape(B,[],1) at the end if you need the output as a column vector.

Delete repeated values of different data types from cell array

I have a list of cell array with many repeated values, which includes strings, sample time, saturation upper limit and lower limit.
For example:
MyValues={ 'Lookc_at_the_stars'
'Lookc_how_they_shine'
'forc_you'
'andm_everything_they_do'
'Theym_were_all_yellow'
'COLDPLAY_STOP'
'COLDPLAY_PLAY'
'COLDPLAY_PLAY'
'COLDPLAY_PLAY'
'COLDPLAY_BREAK'
'COLDPLAY_BREAK'
'Lookc_How_they_shinefor_you'
'its_true'
'COLDPLAY_STOP'
'COLDPLAY_STOP' }
And the output what I require is:
NewMyValues = { 'Lookc_at_the_stars'
'Lookc_how_they_shine'
'forc_you'
'andm_everything_they_do'
'Theym_were_all_yellow'
'COLDPLAY_STOP'
'COLDPLAY_PLAY'
'COLDPLAY_BREAK'
'Lookc_How_they_shinefor_you'
'its_true' }
Since I have tried using the function unique, I am not able to get the output as it's giving me an error, saying
"Error using cell/unique
Input A must be a cell array of strings."
MyValues consists of different types of data type values.
Can someone provide me a solution or function code, that I could remove the repeated values?
Here is a loop based solution to extract unique values of a cell array will different types:
MyValues={ 'Lookc_at_the_stars',
'Lookc_how_they_shine',
1,
'forc_you',
'andm_everything_they_do',
'Theym_were_all_yellow',
2,
'COLDPLAY_STOP',
'COLDPLAY_PLAY',
1,
'COLDPLAY_PLAY',
'COLDPLAY_PLAY',
{1 2 3},
'COLDPLAY_BREAK',
{4 3 5},
'COLDPLAY_BREAK',
{1 2 3},
'Lookc_How_they_shinefor_you',
'its_true',
'COLDPLAY_STOP',
'COLDPLAY_STOP' };
N = numel(MyValues);
idx = true(N,1);
for m = 1: N
if idx(m)
for n = (m+1):N
if idx(n) && isequal(MyValues{m}, MyValues{n})
idx(n) = false;
end
end
end
end
result = MyValues(idx);
the result:
result =
{
[1,1] = Lookc_at_the_stars
[1,2] = Lookc_how_they_shine
[1,3] = 1
[1,4] = forc_you
[1,5] = andm_everything_they_do
[1,6] = Theym_were_all_yellow
[1,7] = 2
[1,8] = COLDPLAY_STOP
[1,9] = COLDPLAY_PLAY
[1,10] =
{
[1,1] = 1
[1,2] = 2
[1,3] = 3
}
[1,11] = COLDPLAY_BREAK
[1,12] =
{
[1,1] = 4
[1,2] = 3
[1,3] = 5
}
[1,13] = Lookc_How_they_shinefor_you
[1,14] = its_true
}
The function isequal can compare anything using it all values compared and duplicates removed. so result is a cell array that contains unique values.
Based on the example in the question if you want to have unique cell array of characters you can use cellfun with ischar to check if the cell value is a character array. Then use the logical index to extract them and apply unique.
unique(MyValues(cellfun(#ischar,MyValues)),'stable')
without using stable option the result will be sorted
The cell you supplied in your question only contained strings, so unique can handle it. However, if you add ints, floats or complex numbers to it, the way to go is to convert all the cell elements to strings before calling unique. For example, I'll show you a small strcaster function
function y = strcaster(x)
if ischar(x)
y = x;
elseif isreal(x)
y = num2str(x);
else
if imag(x)>=0
s = '+j';
else
s = '-j';
end
y = [num2str(real(x)),s,num2str(imag(x))];
end
end
and then you can get the unique elements, preserving the order in which they appear in the cell doing the following:
MyValues={'Lookc_at_the_stars',...
'Lookc_how_they_shine',...
'forc_you',...
'andm_everything_they_do',...
'Theym_were_all_yellow',...
'COLDPLAY_STOP',...
'COLDPLAY_PLAY',...
'COLDPLAY_PLAY',...
'COLDPLAY_PLAY',...
'COLDPLAY_BREAK',...
'COLDPLAY_BREAK',...
'Lookc_How_they_shinefor_you',...
'its_true',...
'COLDPLAY_STOP',...
'COLDPLAY_STOP',...
1,...
1.32423,...
complex(-3.,13)};
[u,i] = unique(cellfun(#(x)strcaster(x),MyValues,'uniformoutput',false),'stable');
disp(MyValues(i))
Edit
Based on your comment, it is clear that the MyValues cell contains other cells, which was not clear from your question's example. The best way to get the unique values in MyValues is still casting the contents to strings. The JSON protocol will allow you to convert almost any data type to a string, so I recommend using matlab's jsonencode function in the following way:
MyValues={'Lookc_at_the_stars',...
'Lookc_how_they_shine',...
'forc_you',...
'andm_everything_they_do',...
'Theym_were_all_yellow',...
'COLDPLAY_STOP',...
'COLDPLAY_PLAY',...
'COLDPLAY_PLAY',...
'COLDPLAY_PLAY',...
'COLDPLAY_BREAK',...
'COLDPLAY_BREAK',...
'Lookc_How_they_shinefor_you',...
'its_true',...
'COLDPLAY_STOP',...
'COLDPLAY_STOP',...
1,...
1.32423,...
[1,23,4,4;5,3,2,1],...
{'bla',1324,{'12',123}},...
struct('NextTime','Provide a complete working example in the question')};
[u,i] = unique(cellfun(#(x)jsonencode(x),MyValues,'uniformoutput',false),'stable');
disp(MyValues(i))

Matlab find string within cell array

I have a cell array (n-by-1 dimension) containing both strings and cells, which looks something like this
{
{'r1'} % -> cell content is in format 'char'
{'r2'} % -> cell content is in format 'char'
{1x2 cell} % -> cell content is a cell array: [{'r1'}{'r2'}]
{'r3'} % -> cell content is in format 'char'
{1x2 cell} % -> cell content is a cell array: [{'r1'}{'r3'}]
{1x2 cell} % -> cell content is a cell array: [{'r2'}{'r3'}]
{1x3 cell} % -> cell content is a cell array: [{'r1'}{'r2'}{'r3'}]
...
}
I need to find the row-index where the some string is included, e.g. 'r2'. I usually use strfind for this purpose which works great if the cell array has a consistent format (hence 'char'-format within each cell).
Is there any way to apply this function to the cell array structure which is displayed above?
Thanks!
EDIT: Please find attached three images showing the data structure that I am using, since I am not sure how to exactly show/explain the hierarchies and layers of the cell array in text. Hope that helps. Also find attached the outcome of the code.
Code used:
change = 'r1.m';
srch = cellfun(#(x) strfind(x, change), strats, 'UniformOutput', false);
stringInRow = cellfun(#(x) numel(x) == 1 || (numel(x)>1)*numel(cell2mat(x))>0, srch);
rows = find(stringInRow);
You could use two subsequent cellfun calls: one to perform the string search (cell by cell), and one to evaluate it (found string true or not false?)
%// example data
c{1} = 'r1';
c{2} = 'r2';
c{3}{1} = 'r1'; c{3}{2} = 'r2';
c{4} = 'r3';
c{5}{1} = 'r1'; c{5}{2} = 'r3';
%// example search
searchForString = 'r2';
srch = cellfun(#(x) strfind(x, searchForString), c, 'UniformOutput', false);
stringInRow = ...
cellfun(#(x) numel(x) == 1 || (numel(x)>1)*numel(cell2mat(x))>0, srch);
%// ^-. short-circuit scalars here ^
%// |
%// since cell2mat is valid only for cells or empty arrays
With resulting stringInRow:
stringInRow =
0 1 1 0 0
If you want to explicitly list the rows, you can just make use of find on the stringInRow boolean vector
>> foundStringInRows = find(stringInRow)
foundStringInRows =
2 3

How do I convert a cell array w/ different data formats to a matrix in Matlab?

So my main objective is to take a matrix of form
matrix = [a, 1; b, 2; c, 3]
and a list of identifiers in matrix[:,1]
list = [a; c]
and generate a new matrix
new_matrix = [a, 1;c, 3]
My problem is I need to import the data that would be used in 'matrix' from a tab-delimited text file. To get this data into Matlab I use the code:
matrix_open = fopen(fn_matrix, 'r');
matrix = textscan(matrix_open, '%c %d', 'Delimiter', '\t');
which outputs a cell array of two 3x1 arrays. I want to get this into one 3x2 matrix where the first column is a character, and the second column an integer (these data formats will be different in my implementation).
So far I've tried the code:
matrix_1 = cell2mat(matrix(1,1));
matrix_2 = cell2mat(matrix(1,2));
matrix = horzcat(matrix_1, matrix_2)
but this is returning a 3x2 matrix where the second column is empty.
If I just use
cell2mat(matrix)
it says it can't do it because of the different data formats.
Thanks!
This is the help of matlab for the cell2mat function:
cell2mat Convert the contents of a cell array into a single matrix.
M = cell2mat(C) converts a multidimensional cell array with contents of
the same data type into a single matrix. The contents of C must be able
to concatenate into a hyperrectangle. Moreover, for each pair of
neighboring cells, the dimensions of the cell's contents must match,
excluding the dimension in which the cells are neighbors. This constraint
must hold true for neighboring cells along all of the cell array's
dimensions.
From what I understand the contents you want to put in a matrix should be of the same type otherwise why do you want a matrix? you could simply create a new cell array.
It's not possible to have a normal matrix with characters and numbers. That's why cell2mat won't work here. But you can store different datatypes in a cell-array. Use cellstr for the strings/characters and num2cell for the integers to convert the contents of matrix. If you have other datatypes, use an appropriate function for this step. Then assign them to the columns of an empty cell-array.
Here is the code:
fn_matrix = 'data.txt';
matrix_open = fopen(fn_matrix, 'r');
matrix = textscan(matrix_open, '%c %d', 'Delimiter', '\t');
X = cell(size(matrix{1},1),2);
X(:,1) = cellstr(matrix{1});
X(:,2) = num2cell(matrix{2});
The result:
X =
'a' [1]
'b' [2]
'c' [3]
Now we can do the second part of the question. Extracting the entries where the letter matches with one of the list. Therefore you can use ismember and logical indexing like this:
list = ['a'; 'c'];
sel = ismember(X(:,1),list);
Y(:,1) = X(sel,1);
Y(:,2) = X(sel,2);
The result here:
Y =
'a' [1]
'c' [3]

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.

Resources