How to call the dynamic variable that created from looping in Matlab? - matlab

I have 4 array create by using looping method:
n=4;
for i=1:n
eval(['Bucket' num2str(i) '= []'])
end
So the array of the output is:
Bucket1=[]
Bucket2=[]
Bucket3=[]
Bucket4=[]
then if I have a looping function for example:
while a<n
Bucket1 = 'Hello world';
a=a+1;
end
So how i can replace the Bucket1 to a dynamic variable? For example when a is equal to 1 then the Hello World will direct store in Bucket1. That's meant The variable name which is Bucket1 is not hard coding.
Can anyone share ideas with me? because I new to Matlab.

Given that the use of dynamic variable is a bad practice (as stated in the above comments), among the possible "alternative" solution (these also, already suggested in the above comments) the use of the struct data type can be considered coupled with the use of the dynamic field names.
The advantage of the dynamic field names consists in having the possibility to "programmatically" define the names of the variables (which in this case will be the field of the struct) avoiding the potential danger implied by eval.
Also the use of a struct allows to manage its field and their content programmatically by using the very large set of related functions.
In the following "crazy" implementation, the dynamic field names concept is used to create a set of variables as fields of a struct.
In particular, the code allows to create:
a set of variables (struct's field) whose name are defined in a cellarray:
dynamic_vars={'Bucket','another_var','one_more_var'}
for each of the variables, is then possible to specify the number of (that is, for example, 4 Bucket => Bucket_1, Bucket_2, .... The quantity is specified in an array
how_many=[4 3 2]
then it is possible to specify, in a cellarray the type of the variables (double, char, cell)
var_type={'double' 'char' 'cell'}
for each of the above varaibles / struct's field is possible to specify a way to initialize them through functions such as zeros, nan, ones or a string
init_set={'NaN' 'Hellp World' 'zeros'}
to complete the definition and initialization of the variables, it is possible to set their size using a cellarray:
var_dim={[2 3] -1 [1 3] [2 3]}
This is the full code:
% Define the name of the variable
dynamic_vars={'Bucket','another_var','one_more_var'}
% Define how many variables to be created with the "dynamic_vars" names
how_many=[4 3 2]
% Define the type of the variable to be created
var_type={'double' 'char' 'cell'}
% Define the function or string to be used to initialize the variables
init_set={'NaN' 'Hellp World' 'zeros'}
%init_set={'NaN' 'Hellp World' 'char'}
% Define the size of the dynamic_vars tobe created
% In the case of cellarray:
% if cellarray of "number" two dimension have to be provided:
% size of the cellarray
% size of the content of the cellarray
% if cellarray of string to specify:
% the size of the cellarray
% the string to be used to initialize the cellarray
var_dim={[2 3] -1 [1 3] [2 3]}
%var_dim={[2 3] -1 [1 3] 'dummy_str'}
n_var=length(dynamic_vars)
% Loop over the variables to be created
for i=1:n_var
% Loop over the number of variables to be created
for j=1:how_many(i)
% Select the data type of the variable
switch(var_type{i})
% Create the i-th variable of the j-th type and iknitialize it
case 'double'
switch(init_set{i})
case 'zeros'
my_data.([dynamic_vars{i} '_' num2str(j)])=zeros([var_dim{i}])
case 'NaN'
my_data.([dynamic_vars{i} '_' num2str(j)])=nan([var_dim{i}])
case 'ones'
my_data.([dynamic_vars{i} '_' num2str(j)])=ones([var_dim{i}])
case 'rand'
my_data.([dynamic_vars{i} '_' num2str(j)])=rand([var_dim{i}])
otherwise
disp('ERROR: Unvalid init_set')
return
end
case 'char'
my_data.([dynamic_vars{i} '_' num2str(j)])=init_set{i}
case 'cell'
switch(init_set{i})
case 'char'
my_data.([dynamic_vars{i} '_' num2str(j)])=repmat({var_dim{i+1}},[var_dim{i}])
case 'zeros'
my_data.([dynamic_vars{i} '_' num2str(j)])=repmat({zeros(var_dim{i+1})},[var_dim{i}])
case 'NaN'
my_data.([dynamic_vars{i} '_' num2str(j)])=repmat({nan(var_dim{i+1})},[var_dim{i}])
case 'ones'
my_data.([dynamic_vars{i} '_' num2str(j)])=repmat({ones(var_dim{i+1})},[var_dim{i}])
case 'rand'
my_data.([dynamic_vars{i} '_' num2str(j)])=repmat({rand(var_dim{i+1})},[var_dim{i}])
otherwise
disp('ERROR: Unvalid init_set')
return
end
otherwise
disp('ERROR: Unvalid data type')
return
end
end
end
my_data
which generate the struct my_data with the following fields:
Bucket_1
Bucket_2
Bucket_3
Bucket_4
another_var_1
another_var_2
another_var_3
one_more_var_1
one_more_var_2
Initialized as follows:
Bucket_1 =
NaN NaN NaN
NaN NaN NaN
Bucket_2 =
NaN NaN NaN
NaN NaN NaN
Bucket_3 =
NaN NaN NaN
NaN NaN NaN
Bucket_4 =
NaN NaN NaN
NaN NaN NaN
another_var_1 = Hellp World
another_var_2 = Hellp World
another_var_3 = Hellp World
one_more_var_1 =
{
[1,1] =
0 0 0
0 0 0
[1,2] =
0 0 0
0 0 0
[1,3] =
0 0 0
0 0 0
}
Caveat
Controls on the consistency of the input (e. g. the length of dynamic_vars and how_many must be the same, ...) have to be added
The code has been tested with Octave 4.2.1

This can be done using assignin as follows,
a=1;
while a<=n
assignin('base',['Bucket', num2str(a)], 'Hello world');
a=a+1;
end

Related

Addressing Composite-Keyed 1NF Matlab Table with Arrays

The Problem
Consider a Table object, tbl, defined below, that holds 1NF normalized information with a 2 part composite key comprised of the unordered tuple of the Species1 and Species2 column values.
% build table ( in place of readtable )
dat = {"example1" "example1" "example1" "example2" "example4" "example3"; ...
"example2" "example3" "example4" "example3" "example2" "example4"; ...
0.1896 -0.0119 -0.0070 0.3257 0.1140 0.2086 };
tbl = cell2table(dat','VariableNames', {'Species1','Species2','k_ij'});
% clear temp vars
clear('dat')
You are given a one dimentional string array, names that holds some set of keys that can appear in either the Species1 or Species2 columns.
% Make an example 1x4 string array
names = ["example1" "example2" "example3" "example4"];
How can a nxn array of values from the k_ij column, as indexed by all combinations of the elements in names, be constructed? Can this be done only with matrix operations?
Assume that any self-self interactions have a zero value; that is k_ij = 0 when the two keys equal one another.
% spec.1 spec.2 spec.3 spec.4
out = [ 0 0.1896 -0.0119 -0.0070; ... % species 1
0.1896 0 0.3257 0.1140; ... % species 2
-0.0119 0.3257 0 0.2086; ... % species 3
-0.0070 0.1140 0.2086 0 ] % species 4
My Aproach Thusfar
My intuition is that it would be best to approach this by forming a nxn array holding all combinations of names, which you can see below.
% make grids come together
[names_1, names_2] = meshgrid(names,names');
% cross join the names
names_mat = reshape( ...
cat(2,names_1',names_2'), ...
length(names), ...
length(names), ...
2);
% clear temp vars
clear('names_1','names_2')
I think that the next step would be to attempt to use the values in names(i,j,:) to address tbl and extract an nxn array values associated from the k_ij column, and to add this to out to get some matrix of the form shown below.
This is the part that I cannot figure out
% spec.1 spec.2 spec.3 spec.4
tmp = [ NaN 0.1896 -0.0119 -0.0070; ... % species 1
NaN NaN 0.3257 NaN ; ... % species 2
NaN NaN NaN 0.2086; ... % species 3
NaN 0.1140 NaN NaN ] % species 4
Because we know that the self-self interactions are always going to be zero, we can set the diagnal to be zero.
tmp(eye(length(names))==1) = 0
this renders a table of the form
% spec.1 spec.2 spec.3 spec.4
tmp = [ 0 0.1896 -0.0119 -0.0070; ... % species 1
NaN 0 0.3257 NaN ; ... % species 2
NaN NaN 0 0.2086; ... % species 3
NaN 0.1140 NaN 0 ] % species 4
Then we can reflect across the diagnal to get the desired output
% grab vals across the diagonal for each value that is NaN
mirror_vals = tmp(isnan(tmp)');
% flip over the diagnal
tmp = tmp';
% stuff grabbed values into NaN indices
tmp(isnan(tmp)) = mirror_vals;
% push to output var
out = tmp;
% clear temporary varaible
clear('tmp','mirror_vals')

Storing the digits after the comma in Matlab

I have a double between 0 and 1 stored in an array in Matlab B.
I want to create a vector t storing the N digits after the comma. If the digits after the comma are <N, then the corresponding element in the vector t should be 0.
Suppose N=10 and B=[0.908789]. Then,
t=[9;0;8;7;8;9;0;0;0;0];
This is the code I am using at the moment
n = fix(rem(B,1)*10^N);
s1 = sprintf('%.0f',n);
ttemp = (s1-'0')';
t=zeros(N,1);
t(1:size(ttemp,1))=ttemp;
but it gives me wrong results.
Indeed, suppose
B=[7.0261e-05] and N=5. The code above gives me
t=[7;0;0;0] without recognising that there e-05.
Any suggestion on how to fix this?
You need to tell sprintf that you'd like all leading 0's to actually be shown if there are fewer than N digits:
Your current way:
sprintf('%.0f', n);
% '7'
The correct way:
s1 = sprintf('%05.f', n);
% '00007'
The general example for any N would be:
s1 = sprintf(['%0', num2str(N), '.f'],n);
The way that you currently have it written, the outpuf of the sprintf command is simply a '7' which when you fill in your output starting at the beginning yields a 7 followed by all 0's (the value you initialized the output to).
If we initialize it to NaN values instead of 0's you can see what the issue is
N = 5;
B = 7.0261e-05;
n = fix(rem(B,1)*10^N);
% 7
s1 = sprintf('%.0f',n);
% '7'
ttemp = (s1 - '0').';
% 7
t = nan(N, 1);
% NaN NaN NaN NaN NaN
t(1:size(ttemp,1)) = ttemp;
% 7 NaN NaN NaN NaN
Alternately, you can keep everything you have and just modify t from the end rather than the beginning
t = zeros(N, 1);
t((end-numel(ttemp)+1):end) = ttemp;
Unsolicited Pointers
' is not the transpose, .' is.
Use numel to determine the number of elements in a vector rather than size since it will work for both row and column vectors

import data from files with unknown format in matlab

I have some files with about 3000 entries including text and numeric data similar to this:
1 0 23 'x' 'x' 'x' 0 0 0 1 1 10.3 54 123.45678 'x' 'x' 'x' ...
i want to import each file data in a separate 1x3000 vector in MatLab but when i use 'importdata' function, it creates a 1x1 struct with two fields (data and textdata).
file_path = '/home/my/file/path';
list_of_files = dir(file_path);
for i = 3:end_
new_data = importdata(fullfile(file_path,list_of_files(i).name));
end
Also i tried to use 'textscan' function but it requires format specification but format of files is unknown (length of each file is constant but it's not clear where we have 'x' or a number)
does anybody have suggestions what to do?
You can not have an array containing both numeric values and strings.
If you want to have both numeric values and strings you have to use cellarray.
Since, as you wrote, you do not like having a struct with two fields, using textscan seems a promising way even if it will be a little complicated.
You can overcame the problem of the format specification by specifying:
the format as string
the delimiter as ' (in you example the text is included within two ')
Your input file will them be stored in a cellarray as sset of strings.
Now you can extract both the numeric values and the strings by scanning the elements of the cellarray.
To identify the numeric values you can try to convert the string in a numeric array with the function str2num:
if the string only contains nueric values, you can store cumulatively the values in an array
if the conversin fails, that means that it was a string, then you can store it cumulatively in a string
You can also set a flag and use it to allows inserting in the numeric output array a value (e. g. NaN) when a string is found; this can allows you to understand where the strings were in the input file.
Also for both the above conditions, you can evaluate the length of the partial arrays of numbers or string and store it in another array.
This allows you to understand where a specific number or string was in the input file.
In the folowing you cn find a possible implementatino of the above described approach.
% Open the input file
fp=fopen('mix_n_s.dat','r');
% Read the input file as a string in a cell array using "'" as a
% delimitator
% c=textscan(fp,'%s','delimiter','''');
c=textscan(fp,'%s','delimiter','''');
% Close the input file
fclose(fp);
% Extract the cell array
a=c{1};
% Initialize the output variables
% Array with the numeric values
numeric_array=[];
% String with the string in the input file
the_strings=[];
% Array with the number of numeric values and strings
the_cnt=[];
% Define the flag for enabling the isertion of NaN in the output numeric
% array in case a string is found
insert_nan=1;
% Scan the cellarray to extract the numbers and the strings
for i=1:length(a)
x=a{i}
% If the i-th element is empty (this occurs when there are at least two
% consecutive string in the input file, do nothing
if(~isempty(x))
% If the i-th element is not empty try to convert it into a numeric array
m=str2num(x);
% If the output is not empty you have read one or more than one
% numeric values
if(~isempty(m));
% Then store them into an array
numeric_array=[numeric_array m];
% The lengh of the array gives you the number of numeric values;
% store it the array
the_cnt=[the_cnt length(m)];
else
% If the conversin failed, you have read a string; store it in a
% string
the_strings=[the_strings ' ' x];
% Store the length of the string in the array; if you store it as
% a negative value, you can recognise it later on
the_cnt=[the_cnt -length(x)];
% if the flag is on, then insert NaN in the numeric array
if(insert_nan)
numeric_array=[numeric_array NaN];
end
end
end
end
numeric_array
the_strings
the_cnt
Based in the input example you've provided (I've slightly modified the strings):
1 0 23 'x' 'x' 'x' 0 0 0 1 1 10.3 54 123.45678 'x' 'x' 'x'
the output is the following (the flag for inssert NaN is on):
numeric_array =
Columns 1 through 7
1.0000 0 23.0000 NaN NaN NaN 0
Columns 8 through 14
0 0 1.0000 1.0000 10.3000 54.0000 123.4568
Columns 15 through 17
NaN NaN NaN
the_strings =
x abcd efghilm x x x
the_cnt =
3 -1 -4 -7 8 -1 -1 -1
It can be interpreted as follows:
looking at the numeric_array array: in the input file
three numeric values, then three strings, then eight numeric values and three strings
looking at the the_cnt array, you can understand the length (discard the - sign) of each string.
Hope this helps.
Qapla'

using indexes to replace NaN based on the whether or not an NaN is in a second vector

I have two vector, "A" and "B". Both can contain NaN elements. I want to replace the "NaN" elements in B with "0" ONLY if the equivalent element in A is a non-NaN. I can do this easily with For- and If-loops, but because I want to understand better about using indexes, and my assumption that using indexes with large data sets would be faster(?), I tried the following:
A = [1,2,3,NaN,5,6,NaN,8,9,10];
B = [NaN,2,3,NaN,5,6,NaN,NaN,9,10];
[Bindex] = isnan(B);
B(~isnan(A(Bindex))) = 0;
This replaced only B(1), but not B(8). What am I missing about using indexes?
If you printed the value of B after those statements you'd see that you're not only not replacing B(8) with zero, but you're also erroneously replacing B(4) with zero, even though A(4) is NaN and so B(4) does not match your zeroing out criterion.
Here's what's going on:
Bindex = isnan(B); # there's no need for brackets around Bindex
The above statement returns a logical array with ones wherever B contains a NaN.
Bindex =
1 0 0 1 0 0 1 1 0 0
Now, when you index into A using Bindex, logical indexing takes place, and only those elements from A which have a corresponding true value in Bindex are extracted. This means the expression A(Bindex) yields
1 NaN NaN 8 # A(1), A(4), A(7), A(8)
So then the expression B(~isnan(A(Bindex))) = 0 is using a 1x4 vector instead of the original 1x10 vector, and ends up setting elements B(1) and B(4) to zero.
What you need is
B(isnan(B) & ~isnan(A)) = 0;
Now the value of B is
B =
0 2 3 NaN 5 6 NaN 0 9 10
I think this should work for you:
B(xor(isnan(A), isnan(B))) = 0

How to convert numeric results in symbols or strings?

this is my problem.
I made an algorithm that makes permutations of certain words. I substituted each word with a numeric value so I can make arithmetical operations with them (e.g. 1 = 'banana' 2 = 'child' 3 = 'car' 4 = 'tree' etc.).
Let's say that after running an algorithm, matlab gave me this matrix as result:
ans = [2,2,1; 4,3,3]
What I never can figure out is how to tell him - substitute digits with symbols and write:
ans = [child,child,banana; tree,car,car] - so I don't have to look up every number in my chart and replace it with a corresponding word!?
If you have an array with your words, and another array with the indices, you can produce an array that replaces every index with the corresponding word like so:
words = {'banana','child','car','tree'};
numbers = [2 2 1;4 3 3];
>> words(numbers)
ans =
'child' 'child' 'banana'
'tree' 'car' 'car'
You can also use the ordinal datatype if you have the statistics toolbox.
>> B = ordinal([2 2 0; 4 3 3], {'banana','child','car','tree'})
B =
child child banana
tree car car
Note that it handles zeros automatically. Then you can do things like:
>> B=='child'
ans =
1 1 0
0 0 0