How to split a cell 1x1 in Matlab? - matlab

Let's say I have a 1x1 cell with this value : 'atcatcaaca' .
My goal is :
Add 1 to 5 'a' beside any 'a'.
Add 1 to 10 'c' beside any 'c'.
Add a random number of 'g' beside any 'g'.
Add a random number of 't' beside any 't'.
For example i have 'atcatcaaca'.My goal is to make it like:'aaaattttcccaattttccaaaaaaaaaacccccccccaa'
My thought is to take the value cell and split it somehow in a matrix:
a | t | a | t | c |a |a | c | a.
Is it possible?And if it is ,how?
The code is :
filename = fullfile(matlabroot,'virus_nucleotitde2.dat');
Z = readtable(filename);
S = table2cell(Z);
num_rows = size (Z,1);
num_cols = size (Z,2);
for i=1:1:num_rows
for j=1:1:num_cols
B = S(i,j);
a=0;
c=0;
g=0;
t=0;
B{1} = num2cell(B{1});
n = randi(6); % Random number between 1 and 6
B{1} = strrep(B{1} , 'a' , repmat('a' , 1, n));
n = randi(11); % Random number between 1 and 11
B{1} = strrep(B{1} , 'c' , repmat('c' , 1, n));
n = randi(11);
B{1} = strrep(B{1} , 'g' , repmat('g' , 1, n));
n = randi(11);
B{1} = strrep(B{1} , 't' , repmat('t' , 1, n));
end
end

Inside the cell, there is a char that you can access with curly brackets:
S = {'ataggatag'};
B = S{1};
disp(B)
Then, strrep is your friend:
n = randi(6); % Random number between 1 and 6
B = strrep(B , 'a' , repmat('a' , 1, n));
n = randi(11); % Random number between 1 and 11
B = strrep(B , 'c' , repmat('c' , 1, n));
n = randi(11);
B = strrep(B , 'g' , repmat('g' , 1, n));
n = randi(11);
B = strrep(B , 't' , repmat('t' , 1, n));
Then put it back into the cell
S{1} = B;
disp(S)
Note that I used 6 as maximum number of 'a's because strrep is going to replace the original a, not adding letters beside it as you asked.
EDIT:
Following OP's edit, here is your solution:
S = {'ataggatag'};
num_rows = size (S,1);
num_cols = size (S,2);
for i=1:1:num_rows
for j=1:1:num_cols
n = randi(6); % Random number between 1 and 6
S{i,j} = strrep(S{i,j} , 'a' , repmat('a' , 1, n));
n = randi(11); % Random number between 1 and 11
S{i,j} = strrep(S{i,j} , 'c' , repmat('c' , 1, n));
n = randi(11);
S{i,j} = strrep(S{i,j} , 'g' , repmat('g' , 1, n));
n = randi(11);
S{i,j} = strrep(S{i,j} , 't' , repmat('t' , 1, n));
end
end
disp(S)

It's already so.. 'a string' is an array of chars, so in order to convert them to a cell array you need to use the usual num2cell function:
>> name_in_1x1_cell_array{1} = 'ataggatag'
name_in_1x1_cell_array =
'ataggatag'
>> name_in_1x1_cell_array{1} = num2cell(name_in_1x1_cell_array{1})
name_in_1x1_cell_array =
{1x9 cell}
You can also access to characters directly, for example you can cycle every character of a string and display it:
name = 'some name';
for i = 1 : length(name)
disp(name(i));
end

Based on your description, not the code:
With the function strrep this is straightforward, as it operates on cell arrays as well:
cell_string = {'atcatcaaca'};
% add a's
cell_string = strrep(cell_string, 'a', repmat('a',1,5));
% add c's
cell_string = strrep(cell_string, 'c', repmat('c',1,10));
% add t's
cell_string = strrep(cell_string, 't', repmat('t',1,randi(10)));
The function repmat is used to duplicate characters.

Related

Merge array rows based on the first digit in a column

I have two arrays, A and B. The first digit of each row is the serial number.
How do I combine A and B to have an array C, such that all rows in A with the same serial number in B are concatenated horizontally?
A = [ 12345;
47542;
32673;
65436;
75343;
23496;
54765 ]
B = [ 23566;
33425;
65438;
75354 ]
y = ismember(A(:,1), B(:,1), 'rows');
t=find(y);
C= [A(t,1:12),B(t,1:12)];
I need C to be:
C = [ 12345, 00000;
23496, 23566;
32673, 33425;
47542, 00000;
54765, 00000;
65436, 00000;
75343, 75354]
My approach would be the following, extract the leading digits of both arrays and compare those:
a=num2str(A)-'0';
b=num2str(B)-'0';
[ida,idb]=ismember(a(:,1),b(:,1));
Now get the sorting index of A
[~,ids]=sort(a(:,1));
Create output array
C=zeros(size(A,1),2);
Finally assign and sort output
C(:,1)=A;
C(ida,2)=B(idb(idb>0));
%sort result
C=C(ids,:)
If it's only the first digit, we only need to check if the first digit (i.e. floor(A/1e4)) matches 0 to 9, and index accordingly...
% Add some zeros at the front to make indexing work with the unmatched ismember outputs
Az = [zero(; A]; Bz = [0; B];
% Find the indices for 0 to 9 within the first digits of A and B
[~,ia] = ismember( 0:9, floor( A/1e4 ) );
[~,ib] = ismember( 0:9, floor( B/1e4 ) );
% Assign to C and discard unmatched rows
C = [Az(ia+1), Bz(ib+1)];
C( all( C==0, 2 ), : ) = [];
Note that keeping things numeric with the floor operation should always be preferable to flipping between numeric and character data with things like num2str...
Edit
You changed the scope of the question by commenting with new data. Here is the same method, written to be more generic so it handles A and B with more columns and different magnitude IDs
% Add some zeros at the front to make indexing work with the unmatched ismember outputs
Az = [zeros(1,size(A,2)); A]; Bz = [zeros(1,size(A,2)); B];
% Function for getting first digit
f = #(x) floor(x./(10.^floor(log10(x))));
% Find the indices for 0 to 9 within the first digits of A and B
[~,ia] = ismember( 0:9, f(A(:,1)) );
[~,ib] = ismember( 0:9, f(B(:,1)) );
% Assign to C and discard unmatched rows
C = [Az(ia+1,:), Bz(ib+1,:)];
C( all( C==0, 2 ), : ) = [];
First of all, the whole script. At first glance, I couldn't find a solution without using loops.
A = [ 12345;
47542;
32673;
65436;
75343;
23496;
54765; ]
B = [ 23566;
33425;
65438;
75354; ]
A = sort(A); % Sort A and B.
B = sort(B);
A_str = int2str(A); % Convert integers to chars.
B_str = int2str(B);
A_sn = A_str(:, 1); % Extract first columns.
B_sn = B_str(:, 1); % Basically, these are the serial numbers.
C = zeros(size(A, 1), size(A, 2) * 2); % Initialize C.
C(:, 1) = A; % First column of C is just A.
for i = 1:length(A_sn) % For all serial numbers in A...
for j = 1:length(B_sn) % For all serial numbers in B...
if (A_sn(i) == B_sn(j)) % Check if serial number in B equals the serial number in A.
C(i, 2) = B(j); % If so, set i-th row in C to the corresponding value in B.
end
end
end
C
Results in:
A =
12345
47542
32673
65436
75343
23496
54765
B =
23566
33425
65438
75354
C =
12345 0
23496 23566
32673 33425
47542 0
54765 0
65436 65438
75343 75354

How to combine two matrices column wise to strings separated by comma?

I have two matrices
A = [ 1 3
4 3]
B = [ 2 1
4 1 ]
I want to combine A and B to produce the string array
C = [ "1,2" "3,1"
"4,1" "3,1" ]
How can I do this in MATLAB? I tried it this way
for i = 1: 4;
for j = 1: 4;
fprintf('%0.2f,%0.2f\n',A(i,j),B(i,j) )
end
end
Appreciate your suggestions !
A = [1 3; 4 3];
B = [2 1; 4 1];
C = A + "," + B
C =
% 2×2 string array
% "1,2" "3,1"
% "4,4" "3,1"
The first thing to note, is that there is a difference between strings "string" and character arrays 'character array'. Whereas strings are one entity, the character array is an array of characters.
Thus you can make the following assignment
A(1) = "Hello";
but not
B(1) = 'Hello';
because the B(1) is one value, and 'Hello' is 5 values (H,e,l,l,o).
Secondly, you cannot use fprintf as you suggest in the comments as it only prints (as in its name) and the variable returned by fprintf is the number of characters printed. Instead, to construct the string use strcat together with num2str, such that you get:
A = rand(2); %some matrices
B = rand(2);
for i = 1:2
for j = 1:2
C(i,j) = strcat(num2str(A(i,j)),",",num2str(B(i,j)));
end
end
EDIT: If you are anyway going to interchange the comma for \pm in LaTeX, you can just do it when constructing C by using
C(i,j) = strcat(num2str(A(i,j)),"\pm",num2str(B(i,j)))
instead.

Matlab if loop function, How to improve this function?

I am new to matlab and I am trying to figure how to write the following function in a smart/efficient way.
First I create a matrix y with entries HL, and every line is a permutation of a predefined length n.
For example, for n=3 I get the first line of the matrix y : H H H. Then I want for each line, to create a matrix of size n x n where for example the entry (1,2) corresponds to a variable which links entry y(1,1) with y(1,2) , and entry y(3,2) corresponds to a variable which links entry y(1,3) with y(1,2). Is this possible?
function A1=mystupidfunction(s , n)
%n is the number of agents and s is the number of state, this function
%returns the matrix of influence. Stupid code must be improved to work for
%n agents
x = 'HL'; %// Set of possible types
K = n; %// Length of each permutation
%// Create all possible permutations (with repetition) of letters stored in x
C = cell(K, 1); %// Preallocate a cell array
[C{:}] = ndgrid(x);
y = cellfun(#(x){x(:)}, C);
y = [y{:}];
A1 = sym('A1',[n n], 'positive' );
syms H L A_HH A_HL A_LH A_LL
for k=s
for i=1:n
for j=1:n
if ( y(k,1)==H) && ( y(k,2)==H) && (y(k,3)==H)
A1(i,j)=A_HH
elseif ( y(k,1)==L) && ( y(k,2)==L) && (y(k,3)==L)
A1(i,j)=A_LL
elseif ( y(k,1)==H) && ( y(k,2)==L) && (y(k,3)==L)
A1(1,1)=A_HH
A1(1,2)=A_HL
A1(1,3)=A_HL
A1(2,1)=A_LH
A1(3,1)=A_LH
A1(2,2)=A_LL
A1(2,3)=A_LL
A1(3,3)=A_LL
A1(3,2)=A_LL
elseif ( y(k,1)==H) && ( y(k,2)==H) && (y(k,3)==L)
A1(1,1)=A_HH
A1(1,2)=A_HH
A1(1,3)=A_HL
A1(2,1)=A_HH
A1(3,1)=A_LH
A1(2,2)=A_HH
A1(2,3)=A_HL
A1(3,3)=A_LL
A1(3,2)=A_LH
elseif ( y(k,1)==L) && ( y(k,2)==L) && (y(k,3)==H)
A1(1,1)=A_LL
A1(1,2)=A_LL
A1(1,3)=A_LH
A1(2,1)=A_LL
A1(3,1)=A_LH
A1(2,2)=A_LL
A1(2,3)=A_LH
A1(3,3)=A_HH
A1(3,2)=A_HL
elseif ( y(k,1)==L) && ( y(k,2)==H) && (y(k,3)==H)
A1(1,1)=A_LL
A1(1,2)=A_LH
A1(1,3)=A_LH
A1(2,1)=A_HL
A1(3,1)=A_HL
A1(2,2)=A_HH
A1(2,3)=A_HH
A1(3,3)=A_HH
A1(3,2)=A_HH
elseif ( y(k,1)==L) && ( y(k,2)==H) && (y(k,3)==L)
A1(1,1)=A_LL
A1(1,2)=A_LH
A1(1,3)=A_LL
A1(2,1)=A_HL
A1(3,1)=A_LL
A1(2,2)=A_HH
A1(2,3)=A_HL
A1(3,3)=A_LL
A1(3,2)=A_LH
elseif ( y(k,1)==H) && ( y(k,2)==L) && (y(k,3)==H)
A1(1,1)=A_HH
A1(1,2)=A_HL
A1(1,3)=A_HH
A1(2,1)=A_LH
A1(3,1)=A_HH
A1(2,2)=A_LL
A1(2,3)=A_HL
A1(3,3)=A_HH
A1(3,2)=A_HL
else A(i,j)=0
end
end
end
end
For example when n=3 and s=1, then the function returns:
A =
[ A_HH, A_HH, A_HH]
[ A_HH, A_HH, A_HH]
[ A_HH, A_HH, A_HH]
notes:
C = cell(K, 1); %// Preallocate a cell array
[C{:}] = ndgrid(x); %// Create K grids of values
y = cellfun(#(x){x(:)}, C); %// Convert grids to column vectors
y = [y{:}];
the output is for n=3 :
y =
HHH
LHH
HLH
LLH
HHL
LHL
HLL
LLL
s is just a scalar that indicates the number of line in the matrix y (which corresponds to a "state")
if you only have 2 states H and L, as you said in comment you could just as well use 0 and 1, so a binary logic.
To get your y combinations, just count in binary until you have the right number of digit and convert each bit to the state you decide:
So for order n=3 you would have:
n = 3 ;
a = de2bi( (0:2^n-1).' )
which gives you all 3 digits binary combinations:
a =
0 0 0
1 0 0
0 1 0
1 1 0
0 0 1
1 0 1
0 1 1
1 1 1
If you want them in ascii format, you can then convert them:
b = char( ones(size(a))* 'L') ;
b(~a) = 'H' ;
To obtain:
b =
HHH
LHH
HLH
LLH
HHL
LHL
HLL
LLL
So if you want to keep a "ascii" character logic (and output), this could do the job:
function out = combiadjacent( k , n )
yb = de2bi( (0:2^n-1).' ) ; %'// get the combinations
y = char( ones(size(yb))* 'L') ;
y(~yb) = 'H' ;
A = char( zeros(n,2*n) ) ;
for col=1:n
Acol = [col col+1] + (col-1) ;
A(:,Acol) = [y(k,col)*ones(n,1) y(k,:).'] ;
end
out = reshape( cellstr( reshape(A.',2,[]).' ) , n , n ).' ;
Will give you a cell array as output like:
>> A = combiadjacent( 4 , 3 )
A =
'LL' 'LL' 'HL'
'LL' 'LL' 'HL'
'LH' 'LH' 'HH'
However, if you are not picky about the exact output format, the solution below will probably run significantly faster:
function out = combiadjacent( k , n )
y = de2bi( (0:2^n-1).' ) ; %'// get the combinations
b = ones(n,1)*y(k,:) ;
%// use that to get a cell array of characters
out = cellfun( #(a,b) char(cat(2,a+65,b+65)) , num2cell(b) ,num2cell(b.'),'uni',0) ;
%'// or use that to get a cell array of double in output (even faster)
%// out = cellfun( #(a,b) cat(2,a,b) , num2cell(b) ,num2cell(b.'),'uni',0)
%// or that to get a cell array of boolean
%// out = cellfun( #(a,b) logical(cat(2,a,b)) , num2cell(b) ,num2cell(b.'),'uni',0) ;
Which will give you
>> A = combiadjacent( 4 , 3 )
A =
'BB' 'BB' 'AB'
'BB' 'BB' 'AB'
'BA' 'BA' 'AA'
note: Whatever solution you choose, it would be prudent to add a checking condition for k to make sure the user will not request a line which doesn't exist.

How to create vector of binary values based on correspondence between two other vectors in MATLAB [duplicate]

I'm developing a program with MatLab that calculates powers of numbers, adds them together, and then sees if any of the first set of numbers (numbers to powers) equals any of the added numbers to powers. I'm trying to check this for each value in the first array, however, I am getting an output like this:
m =
1
128
2187
16384
78125
279936
823543
2097152
4782969
10000000
for each m value, which is just the result of a simple for loop of the array. So when I go to check if m is in the array, it checks is [1, 128,2187,16384,78125...] in the array, and the answer is no. How can I get it to evaluate each individual entry, like this:
Array n is [1,128,2187,16384]
for m = n
m = 1
Is m in array? No
m = 128
Is m in array? No
m = 2187
Is m in array? Yes
m = 16384
Is m in array? No
end
My code is below:
C = [];
D = [];
E = [];
F = [];
numbers1 = [];
numbers2 = [];
numbers = 10;
powers = 10;
for i = 1:numbers
for j = 3:powers
C = [C;i^j];
end
C = transpose(C);
D = [D;C];
C = [];
end
[~,b] = unique(D(:,1)); % indices to unique values in first column of D
D(b,:); % values at these rows
for i = D
for a = D
E = [E;i+a];
end
E = transpose(E);
F = [F;E];
E = [];
end
[~,b] = unique(F(:,1)); % indices to unique values in first column of F
F(b,:); % values at these rows
for m = D % this is the for loop mentioned above
m
end
Example vectors:
>> m = [1 3 5 9];
n = [5 2 1 4 8];
To check if each element of vector m is in n, use ismember:
>>ismember(m,n)
ans =
1 0 1 0
To get the values, not the indices: use logical indexing on m:
>> m(ismember(m,n))
ans =
1 5
or directly use intersect:
>> intersect(m,n)
ans =
1 5

How to generalized the formula in matlab

I want to vary the condition for the n-th vector to cover a range of i-values (something like i=2:27).
N=51;
num =2;
W = 3;
i = 2;
string1 = '[';
for n = num:-1:1
string1 = [ string1 'a' num2str(n) ' '];
end
string1 = [ string1 '] = ndgrid(1:W);'];
string2 = 'ind = find(';
for n = 2:num
string2 = [ string2 'a' num2str(n) '>=a' num2str(n-1) '&' ];
end
for n = 1:num
string2 = [ string2 'a' num2str(n) '+'];
end
string2 = [ string2(1:end-1) '==i);' ];
string3 = 'C = [ ';
for n = 1:num
string3 = [ string3 'a' num2str(n) '(ind) ' ];
end
string3 = [ string3 ']' ];
eval(string1);
eval(string2);
eval(string3);
Unfortunately, I have difficulties in understanding how this is a generalization of my initial construct.
Ultimately, I need the matrix p2 (which selects combinations of a1, a2 to an) in a probability analysis.
Here's how you can do it:
N = 5; % number of columns, this was your a1 ... a5
W=3; % unchanged to first example in question
i=6; % unchanged to first example in question
% the following will create a matrix with N-1 columns
% because the last column is determined by the sum of the columns before it
% the a1 .. an-1 columns contains all possible permutations of 1:W
% (this code can be found on the internet)
for ii=1:N-1
dset{1,ii}=1:W;
end
n=numel(dset);
a=cell(n,1);
[a{1:n}]=ndgrid(dset{end:-1:1});
a=reshape(cat(n+1,a{:}),[],n);
a=a(:,end:-1:1);
% next, we sort the rows ascending
% because for you, 1-1-2 is the same as 1-2-1
% and after sorting, we pick the unique rows
a = unique(sort(a,2),'rows');
% next, we populate the last column
% and select those that match your criterion
% in a matrix p2n
p2n = [];
for ii=1:size(a,1)
a(ii,N) = i - sum(a(ii,1:N-1));
if(a(ii,N-1) <= a(ii,N) && a(ii,N)<=W)
p2n=[p2n;a(ii,:)];
end
end
See the comments in the code for explanations.
EDIT
If you want to vary N, i and W, use for-loops for example:
for N=2:4
for i=2:27
for W=3:7
% post code starting at line 11 here
% DO NOT DECLARE N, W, i inside the loops again
% Also, introduce a cell to store all `p2n` matrices:
% place this inside the loop but below the code given above
P2n{N,i,W} = p2n;
end
end
end