I have three cell arrays of strings and I want to find all possible combinations of the three. So if I have:
One= Two= Three=
[A B [M N [W X
C D] O P] Y Z]
I want to be able to find all combinations, which would give me something like:
Four=
[AMW AMX AMY AMZ ANW ANX ANY ANZ AOW AOX AOY AOZ APW APX APY APZ
BMW BMX BMY BMZ BNW BNX BNY BNZ BOW BOX BOY BOZ BPW BPX BPY BPZ
etc.
etc.]
Is there a simple way to do this or will I have to somehow change the strings to integer values?
So, you have three cell arrays:
One = {'A' 'B' 'C' 'D'};
Two = {'M' 'N' 'O' 'P'};
Three = {'W' 'X' 'Y' 'Z'};
We can try to work with their indices
a = 1:length(One);
ind = combvec(a,a,a);
ind would be the matrix with all the combinations of three numbers from 1 to 4, e.g. 111 112 113 114 211 212 213 214 etc. According to combinatorics, its dimensions would be 3x64. The indices correspond to the letters in your cell array, i.e. 214 would correspond to 'BMZ' combination.
EDIT, developed an easy way to generate the combinations without combvec with help of #LuisMendo 's answer:
a=1:4;
[A,B,C] = ndgrid(a,a,a);
ind = [A(:),B(:),C(:)]';
Then you create the blank cell array with length equal to 64 - that's how many combinations of three letters you are expected to get. Finally, you start a loop that concatenates the letters according to the combination in ind array:
Four = cell(1,length(ind(1,:)));
for i = 1:length(ind(1,:))
Four(i) = strcat(One(ind(1,i)),Two(ind(2,i)),Three(ind(3,i)));
end
So, you obtain:
Four =
'AMW' 'BMW' 'CMW' 'DMW' 'ANW' ...
Related
My first array called removed is a 61 x 1 array, my second array called kept is a 45 x 1 array, my third array called deleted_rxns1 is a 16 x 1 array
I am using;
combo=vertcat(removed, kept, deleted_rxns1)
However, this just combines them altogether into one 122 x 1 array. I need three columns one for each of the removed, kept and deleted_rxns1.
I also need to preferably align them via their common row name, and have NA where this doesn't happen. kept have some rows named the same as removed, whilst deleted_rxns1 has some of the same rows names as removed. It would be handy if the final output could look like this;
Removed Kept Deleted
NH3 NA NH3
CH4 CH4 NA
02 02 NA
C02 NA CO2
If this is not possible, I would still prefer to have a matrix with three columns. Please could anybody help?
Thank-you
Seeing the arrays are not of the same size, you can not concatenate them into a 2D matrix.
You can however, use a similar construction to what you have requested via cell arrays:
c = {removed, kept, deleted_rxns1};
% c{1} == removed
% c{2} == kept
% c{3} == deleted_rxns1
As for you second request, you have not provided nearly enough information to classify which rows from each column adhere to each other - so I can't really help until you supply more information.
Here is the code that works fine for your toy example:
clc;
clear;
% vectors
removed = cellstr(['NH3';'CH4';'O2';'CO2']);
kept = cellstr(['CH4';'O2']);
deleted = cellstr(['NH3';'CO2']);
% match vectors in cell array by columns
M = num2cell(NA*ones(4,3));
M(:,1) = removed;
M(find(ismember(M(:,1),kept)),2) = kept;
M(find(ismember(M(:,1),deleted)),3) = deleted;
and then you will get
䠜M =
{
[1,1] = NH3
[2,1] = CH4
[3,1] = O2
[4,1] = CO2
[1,2] = NA
[2,2] = CH4
[3,2] = O2
[4,2] = NA
[1,3] = NH3
[2,3] = NA
[3,3] = NA
[4,3] = CO2
}
which looks like
I ran the code above in Octave, but I believe it should also work in Matlab.
Consider that I have a table of such type in MATLAB:
Location String Number
1 a 26
1 b 361
2 c 28
2 a 45
3 a 78
4 b 82
I would like to create a script which returns only 3 rows, which would include the largest Number for each string. So in this case the table returned would be the following:
Location String Number
3 a 78
1 b 361
2 c 28
The actual table that I want to tackle is much greater, though I wrote this like that for simplicity. Any ideas on how this task can be tackled? Thank you in advance for your time!
You could use splitapply, with an id for each row.
Please see the comments for details...
% Assign unique ID to each row
tbl.id = (1:size(tbl,1))';
% Get groups of the different strings
g = findgroups(tbl.String);
% create function which gets id of max within each group
% f must take arguments corresponding to each splitapply table column
f = #(num,id) id(find(num == max(num), 1));
% Use splitapply to apply the function f to all different groups
idx = splitapply( f, tbl(:,{'Number','id'}), g );
% Collect rows
outTbl = tbl(idx, {'Location', 'String', 'Number'});
>> outTbl =
Location String Number
3 'a' 78
1 'b' 361
2 'c' 28
Or just a simple loop. This loop is only over the unique values of String so should be pretty quick.
u = unique(tbl.String);
c = cell(numel(u), size(tbl,2));
for ii = 1:numel(u)
temp = tbl(strcmp(tbl.String, u{ii}),:);
[~, idx] = max(temp.Number);
c(ii,:) = table2cell(temp(idx,:));
end
outTbl = cell2table(c, 'VariableNames', tbl.Properties.VariableNames);
Finding max values of each string my idea is.
Create a vector of all your strings and include them only one time. Something like:
strs=['a','b','c'];
Then create a vector that will store maximum value of each string:
n=length(strs);
max_values=zeros(1,n);
Now create a loop with the size of the whole data to compare current max_value with the current value and substitute if current_value>max_value:
for i=1:your_table_size
m=find(strs==current_table_string); % This finds the index of max_values
if max_values(m)<current_table_Number % This the the i_th row table_number
max_values(m)=current_table_Number;
end
end
I have 2 cells, B and M. B is nx1 cell and M is a nx2 cell. Some of the values in B are blanks. The rest is the same as M{:,2}. Something like this:
B=
'beta001.img'
'beta002.img'
[]
[]
[]
'beta006.img'
[]
...
And
M=
67 'beta001.img'
89 'beta002.img'
34 'beta003.img'
14 'beta004.img'
15 'beta005.img'
32 'beta006.img'
...
I would like to create a cell C that contains values from the 1st column of M but only if the corresponding values in second column match those in B. Basically, with the example above, C should be:
67
89
32
I can see there are at least two options. The easiest would be doing a horzcat of B and M then get rid of all the rows that contain a blank. I tried:
C=horzcat(B,M);
C=R(~cellfun('isempty',C));
Unfortunately that didn't work. Since I want to learn how to use ismember, the second option is to use that to compare across B and M. Could anyone help me?
Your approach corrected:
This concatenates the matrices. Then extracts the rows, where there aren't any empty entries and then the second column of the result.
C = horzcat(B,M);
C = C(~any(cellfun('isempty',C),2),:);
C = cell2mat(C(:,2));
But you don't need to concatenate the cell-arrays to achieve what you are doing.
Simplified approach:
You can just find the lines where B is not empty, and then take the first column of M of said corresponding lines.
isBnotEmpty = ~cellfun(#isempty, B);
C = cell2mat(M(isBnotEmpty,1));
I have a question about bar graph in Matlab.
I have this,
a=[20 86 3];
but each number corresponds to one letter like,
20 -->a
86 -->b
3 -->c
and then I make the bar graph,
bar(a)
set(gca,'XTickLabel',{'a','b','c'})
Is there a way to sort a but keep the letter that corresponds to each number?
I thought making a dictionary but I don't know how to make it in MATLAB
Thank you.
Try this,
a = [20 86 3];
l = {'a' , 'b' , 'c'};
[a,ind] = sort(a);
l = l(ind);
When you use [a,ind] = sort(a); the sorted a will be saved in a and the indexes will be saved in ind, which can be used to sort l as well.
i have the following matrices
letter=[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ...
a b c d e f g h ii jj k l m o p q r s t u v w x y z];
number=[one two three four five six seven eight nine zero];
character =[number letter];
Character becomes a matrix of 42 by 1464, but i would like to break it into cells of 42 by 24 using mat2cell.
How can i please do it, every time i try i get an error????
The example matrices you give don't make much sense given the problem you describe in the text. If you have a matrix of size 42-by-1464, and you want to use MAT2CELL to break it up into a cell array containing elements that are 42-by-24, you can do the following:
mat = repmat('a',42,1464); %# A sample character matrix containing all 'a's
[nRows nCols] = size(mat); %# Get the number of rows and columns in mat
nSubCols = 24; %# The number of desired columns in each submatrix
cellArray = mat2cell(mat,nRows,nSubCols.*ones(1,nCols/nSubCols));
The second input to MAT2CELL defines how the rows will be broken up among cells along the row dimension. In this case, a single value of 42 (i.e. nRows) indicates that the resulting cell array will have one row and the cells will contain matrices with 42 rows.
The third input to MAT2CELL defines how the columns will be broken up among cells along the column dimension. In this case, it is a 61 element (i.e. nCols/nSubCols) row vector whose elements all contain the number 24 (i.e. nSubCols). This indicates that the resulting cell array will have 61 columns and the cells will contain matrices with 24 columns.
The net result is that cellArray ends up being a 1-by-61 cell array where each cell contains a 42-by-24 submatrix of mat.
The above works when nCols is an exact multiple of nSubCols. If it isn't, then you will have to distribute columns to your cells in a heterogeneous manner (i.e. each cell may have a different number of columns in its submatrix). Some ways to deal with such a situation are discussed in this other SO question.