This question already has answers here:
Changing variable name in loop
(2 answers)
How to turn a string into a variable name within a loop?
(1 answer)
Closed 8 months ago.
In Matlab, I want to create a series of variables based on an array of strings.
As a simplified example, from the given matrixes A1, A2, B1, and B2, I want to create variables A and B as their corresponding combined matrixes. Kindly teach me how to do that. It is very much appreciated.
I have tried the below code, which does not work.
% Simplified examples of given matrixes
A1 = [1;2];
A2 = [3;4];
B1 = [5;6];
B2 = [7;8];
% What I need
ATest = cat(1, A1, A2);
BTest = cat(1, B1, B2);
% I have many of A, B, …, thus looking for a loop of string array, but below trying does not work.
VarList = {'A', 'B'};
for ivar = 1:length(VarList)
eval(['%d = cat(1, %d1, %d2);', VarList(ivar)));
end
Added: (a temporary solution for my desire). Note the use of VarList{ivar} instead of VarList(ivar). I should note it as temporary since caution (for the problem of dynamic variables) may be needed.
VarList = {'A', 'B'};
for ivar = 1:length(VarList)
v = VarList{ivar};
eval([v '=cat(1,' v '1,' v '2);']);
end
Related
The code
ite = 5 ;
cell = 5;
MRJIT = xlsread('5 Node.xlsm',1,'L62: P67');
max_col = 5 ;
for m=1:ite
for n=1:max_col
a = randi(cell)
b = randi(cell)
while (eq(a,b) ||(MRJIT(a,n)==0 && MRJIT(b,n)==0))
if (a~=b)&&(MRJIT(a,n)> 0 || MRJIT(b,n)>0)
break;
end
a = randi(cell)
b = randi(cell)
end
MRJIT([a,n b,n]) = MRJIT([b,n a,n]) %swap value
end
end
Code explanation
there are 5 column on this table, 5 node.xls
the point of this code is to swap values between 2 cell on each column from the table above that are selected by choosing 2 random number that is a and b but only if one of the selected cell value is not zero, if both of the cell values equal to zero, it will need to select another 2 random number until the one of the selected cells values is not equal to zero
The Question
1.why does the code stuck in the while loop? when i try to force stop the program, it shows some of the a and b values are not the same or equal to zero, but it kept stuck on the while loop
Why does the program only run on column 1 and not the others?
This statement
MRJIT([a,n b,n]) = MRJIT([b,n a,n])
does not swap two values. [a,n b,n] is the same as [a,n,b,n]. That is, you are addressing three values using linear indexing (one of them twice). Alternatives: use sub2ind to compute linear indices to your two values, so you can swap them in one statement like you tried, or use a temporary variable to store the one value, and swap them indexing one item at the time. There is no direct way in MATLAB to index two elements in one operation, unless the elements are on the same row or column (except using linear indices, of course).
Using the sub2ind alternative, you could write:
a = sub2ind(a,n);
b = sub2ind(b,n)
MRJIT([a,b]) = MRJIT([b,a]);
Note the difference between MRJIT([a,b]) and MRJIT(a,b).
The other alternative is:
tmp = MRJIT(a,n);
MRJIT(a,n) = MRJIT(b,n);
MRJIT(b,n) = tmp;
--
As an aside, you might be able to improve (speed up) the way you find a and b by (not tested):
a = 0;
while(MRJIT(a,n)==0)
a = randi(cell);
end
b = 0;
while (a==b || MRJIT(b,n)==0)
b = randi(cell);
end
I have two string arrays and I want to find where each string from the first array is in the second array, so i tried this:
for i = 1:length(array1);
cmp(i) = strfind(array2,array1(i,:));
end
This doesn't seem to work and I get an error: "must be one row".
Just for the sake of completeness, an array of strings is nothing but a char matrix. This can be quite restrictive because all of your strings must have the same number of elements. And that's what #neerad29 solution is all about.
However, instead of an array of strings you might want to consider a cell array of strings, in which every string can be arbitrarily long. I will report the very same #neerad29 solution, but with cell arrays. The code will also look a little bit smarter:
a = {'abcd'; 'efgh'; 'ijkl'};
b = {'efgh'; 'abcd'; 'ijkl'};
pos=[];
for i=1:size(a,1)
AreStringFound=cellfun(#(x) strcmp(x,a(i,:)),b);
pos=[pos find(AreStringFound)];
end
But some additional words might be needed:
pos will contain the indices, 2 1 3 in our case, just like #neerad29 's solution
cellfun() is a function which applies a given function, the strcmp() in our case, to every cell of a given cell array. x will be the generic cell from array b which will be compared with a(i,:)
the cellfun() returns a boolean array (AreStringFound) with true in position j if a(i,:) is found in the j-th cell of b and the find() will indeed return the value of j, our proper index. This code is more robust and works also if a given string is found in more than one position in b.
strfind won't work, because it is used to find a string within another string, not within an array of strings. So, how about this:
a = ['abcd'; 'efgh'; 'ijkl'];
b = ['efgh'; 'abcd'; 'ijkl'];
cmp = zeros(1, size(a, 1));
for i = 1:size(a, 1)
for j = 1:size(b, 1)
if strcmp(a(i, :), b(j, :))
cmp(i) = j;
break;
end
end
end
cmp =
2 1 3
Suppose I have a cell array containing strings:
c = {'foo1', 'foo2', 'foo3'}
I now want to add the same suffix "bar" to each string, such that the cell array becomes:
c = {'foo1bar', 'foo2bar', 'foo3bar'}
Is there a shortcut to doing this, without explicitly looping through each element?
strcat operates on cell arrays:
>> c = {'foo1', 'foo2', 'foo3'}
c =
'foo1' 'foo2' 'foo3'
>> c2 = strcat(c,'bar')
c2 =
'foo1bar' 'foo2bar' 'foo3bar'
What about using cellfun:
c=cellfun(#(x) strcat(x, 'bar'), c, 'Uniformoutput', 0);
I don't know if it's faster to run than a loop, but it's less tedious to write.
Edit: apparently strcat handles cell arrays. Use cellfun for functions that don't.
In order to make this question easier to describe I have provided the following example code, which is similar to the actual data I am working with:
clear all
AirT = {rand(32,1),rand(32,1),rand(32,1),rand(32,1)};
SolRad = {rand(32,1),rand(32,1),rand(32,1),rand(32,1)};
Rain = {rand(32,1),rand(32,1),rand(32,1),rand(32,1)};
Location = {'England','Wales','Scotland','Ireland'};
points = {'old','old','old','new'};
CorrVariables = {'AirT','SolRad','Rain'};
for i = 1:length(Location);
Data = #(location) struct('Location',location,CorrVariables{1},AirT{i},...
CorrVariables{2},SolRad{i},CorrVariables{3},Rain{i});
D(i) = Data(Location{i});
end
FieldName = {D.Location};
R = corrcoef([D.AirT],'rows','pairwise');
R_Value = [Location(nchoosek(1:size(R,1),2)) num2cell(nonzeros(tril(R,-1)))];
q = points(nchoosek(1:size(R,1),2));
%to calculate the combination of these points we need to convert the
%cell into a matrix.
Re = [R_Value q];
From this example I would like to create another cell array in column 5 of Re which is dependant on the strings in columns 4 and 5. So, if columns 4 and 5 in Re are equal, such as 'old''old' then column 6 should show 'old'. However, if the cells differ e.g. 'old' 'new' then I would like the new cell array (i.e. column 6 in Re) to state 'old/new'.
How would this be possible?
From your description I think the clearest approach is to use a combination of string concatenation and regular expressions.
First combine columns 4 and 5 into a new column:
newColumn = strcat(Re(:,4), '/', Re(:,5));
Now look for the repeated pattern and replace with the first token matched:
newColumn = regexprep(newColumn, '(\w+)/\1', '$1');
Combine into existing cell matrix:
Re = [Re, newColumn];
What is the quickest way to create an empty cell array of strings ?
cell(n,m)
creates an empty cell array of double.
How about a similar command but creating empty strings ?
Depends on what you want to achieve really. I guess the simplest method would be:
repmat({''},n,m);
Assignment to all cell elements using the colon operator will do the job:
m = 3; n = 5;
C = cell(m,n);
C(:) = {''}
The cell array created by cell(n,m) contains empty matrices, not doubles.
If you really need to pre populate your cell array with empty strings
test = cell(n,m);
test(:) = {''};
test(1,:) = {'1st row'};
test(:,1) = {'1st col'};
This is a super old post but I'd like to add an approach that might be working. I am not sure if it's working in an earlier version of MATLAB. I tried in 2018+ versions and it works.
Instead of using remat, it seems even more convenient and intuitive to start a cell string array like this:
C(1:10) = {''} % Array of empty char
And the same approach can be used to generate cell array with other data types
C(1:10) = {""} % Array of empty string
C(1:10) = {[]} % Array of empty double, same as cell(1,10)
But be careful with scalers
C(1:10) = {1} % an 1x10 cell with all values = {[1]}
C(1:10) = 1 % !!!Error
C(1:10) = '1' % !!!Error
C(1:10) = [] % an 1x0 empty cell array