MATLAB concatenate combination variable length string and vector - matlab

Many near-solutions are online, but nothing exact...
I am building a data matrix vector-by-vector:
OutputMatrix(NextSubject,:)=[OutputVector]
I need to lead each row with the name of the data being processed in that loop. The name has the form:
12345.dat
So if OutputVector=[1 2 3 4] the output should look like:
12345.dat 1 2 3 4
I have tried dozens of solutions, but a few examples:
{char(Filename(i).name) OutputVector}
{strcat((Filename(i).name) OutputVector)}
[Filname(i).name OutputVector]
Any help? Please :)

You can't store a string and a vector in a matrix. However, you can do that in a cell.
So you might consider doing:
OutputCell(NextSubject,:) = { Filename(i).name OutputVector };
The curly braces denote that you are storing the object as a cell.
Often though it is better to store strings and number separately. Something like:
OutputMatrix = [];
OutputFile = {};
...
OutputMatrix(NextSubject,:) = OutputVector;
OutputFile{NextSubject} = Filename(i).name;
Then if you access or select rows from output matrix, use the same index for the cell array:
foo(OutputMatrix(index,:), OutputFile(index))

Related

How to create a new matrix with a for loop in MATLAB?

I am a newbie. I have problem.
I have 20 (1x100) different named vectors. I want to combine these vectors to create a 20x100 matrix with a for loop.
There are the examples of vectors.
namelist=["First","B","New"]
First = [1:100]
B = [1:2:200]
New = [4:4:400]
for i = 1: length(namelist)
new_database(i,1:end) = namelist{i}
end
But, when I want to try this I saw "The end operator must be used within an array index expression." error.
I know I can do same thing with this:
"new_database= [First;B;New]"
but i want to do this with a for loop.
Would you help me how can fix this error? or Would you explain me how can do this?
Your problem is with this line:
new_database(i,1:end) = namelist{i}
the curly braces are used with cells, exclusively and there is no need to use range indexing as you do (i, 1:end)
Generally, it is better practice to assign character arrays or strings to cells.
One question, what are you doing with the 'First', 'New' and 'B' ranges arrays?
Something like:
namelist=["First","B","New"]
First = [1:100];
B = [1:2:200];
New = [4:4:400];
new_database = cell(1, length(namelist));
for i = 1: length(namelist) % or length(new_database)
new_database{i} = namelist(i)
end
which generates this output:
EDIT: My apologies, now I see what you are trying to accomplish. You are building a database from a series of arrays, correct?
Following my previous response, you must consider some points:
1 Your new_database should be square. Regardless of the dimensions of the arrays you are passing to it, if you form a cell from them, you will invariably have empty cells if no data is passed to those rows or columns
2 In some cases, you don't need to use for-loops, where simple indexing might suffice your case problem. Consider the following example using cellstr:
titles = ["Position", "Fruits", "Mythical creatures"]
A = ["One", "Two", "Three"];
B = ["Apple", "Banana", "Durian"];
C = ["Dragon", "Cat", "Hamster"];
db = cell(4, 3);
db(1,:) = cellstr(titles)
db(2:end,1) = cellstr(A)
db(2:end,2) = cellstr(B)
db(2:end,3) = cellstr(C)
which generates this output:

Take string from cell array for name of variable in matlab workspace

I have a large amount of .csv files from my experiments (200+) and previously I have been reading them in seperately and also for later steps in my data handling this is tedious work.
co_15 = csvread('CO_15K.csv',5,0);
co_25 = csvread('CO_25K.csv',5,0);
co2_15 = csvread('CO2_15K.csv',5,0);
co2_80 = csvread('CO2_80K.csv',5,0);
h2o_15 = csvread('H2O_15K.csv',1,0);
etc.....
So I want to make a cell at the beginning of my code looking like this and then a for loop that just reads them automatically.
input = {'co_15' 5;'co_25' 5;...
'co2_15' 5; 'co2_80' 5;...
'h2o_15' 1; 'h2o_140' 1;...
'methanol_15' 5;'methanol_120' 5;'methanol_140' 5;...
'ethanol_15' 5;'ethanol_80' 1;'ethanol_140' 5;...
'co2_ethanol_15' 5 ;'co2_ethanol_80' 5;...
'h2o_ethanol_15' 1 ;'h2o_ethanol_140' 1;...
'methanol_ethanol_15' 5;'methanol_ethanol_120' 5;'methanol_ethanol_140' 5};
for n = 1:size(input,1)
input{n,1} = csvread(strcat(input{n,1},'k.csv'),input{n,2},0);
end
The cell in this code is 19 rows and 2 columns, the rows are all the files and the columns will contain the parameters to handle the data. Now the problem I can't find a solution for is that my first column is a string name and I want that string name to be the name of the variable where csvread writes its data to but the way I set it up now it just overwrites the string in the first column of the cell with the csv data. To be extra clear I want my matlab workspace to have variables with string names in the first column containing the data of my csv files. How do I solve this?
You don't actually want to do this. Even the Mathworks will tell you not to do this. If you are trying to use variable names to keep track of related data like this, there is always a better data structure to hold your data.
One way would be to have a cell array
data = cell(size(input(:,1)));
for n = 1:size(input,1)
data{n} = csvread(strcat(input{n,1},'k.csv'),input{n,2},0);
end
Another good option is to use a struct. You could have a single struct with dynamic field names that correspond to your data.
data = struct();
for n = 1:size(input,1)
data.(input{n,1}) = csvread(strcat(input{n,1},'k.csv'),input{n,2},0);
end
Or actually create an array of structs and hold both the name and the data within the struct.
for n = 1:size(input, 1)
data(n).name = input{n,1};
data(n).data = csvread(strcat(input{n,1},'k.csv'),input{n,2},0);
end
If you absolutly insist on doing this (again, it's is very much not recommended), then you could do it using eval:
for n = 1:size(input, 1)
data = csvread(strcat(input{n,1},'k.csv'),input{n,2},0);
eval([input{n, 1}, '= data;']);
end

Vectorize filtering on matlab cell structures

I have a huge cell vector cc (size: 1xN) of the form:
cc{1} = {'indexString1', 'str_row1col1', 'str_row1col2' }
cc{2} = {'indexString2', 'str_row2col1', 'bighello', 'str_row1col3' }
cc{3} = {'indexString3','str_row3col1'}
cc{4} = {'indexString4','str_row3col1', 'helloWorld'}
I want to traverse each cell and remove specific cells that contain the word "hello", e.g c{4}{2}. Can we do that without for loops keeping the final structure of cc?
Best,
Thoth.
EDIT: From the answers and comments I have seen that the structure of the cell impose some limitations. So any other suggestion to store my data are welcome. I just want to keep together all the cells (e.g. 'str_row1col1', 'str_row1col2') that correspond to the same indexString*n* (e.g. indexString1). I made this edit in case it helps some final reshape.
Using regular expressions, you can obtain a logical array in which zeros represent occurences of the word 'hello' somewhere in the nested cell. As #LuisMendo pointed out, this would be much easier to delete the unwanted cells if they were not nested:
clc
clear
cc{1} = {'str_row1col1', 'str_row1col2' };
cc{2} = {'str_row2col1', 'bighello', 'str_row1col3' };
cc{3} = {'str_row3col1'};
cc{4} = {'str_row3col1', 'helloWorld'};
A = (cellfun(#isempty,regexp([cc{:}],'(\w*hello|hello\w*)','match')))
Gives the following array:
A =
1 1 1 0 1 1 1 0
For the rest I think you would need a loop since the nested cells are not all of the same size. Anyhow I hope it helps you a bit.
EDIT Here is what you can do using a for loop. In order to identify words of interest (earth and water as in your comment below), simply add them to the argument in the call to regexp. This character: | is used to make some sort of list so that Matlab checks all the expressions in the brackets.
Please refer to this page for more infos on regular expressions. There is also a possibility to look for regular expressions with case-sensitivity.
Sample code, in which I added strings containing earth and water:
cc{1} = {'str_row1col1', 'earth!superman' 'str_row1col2' 'DummyString'};
cc{2} = {'str_row2col1', 'bighello', 'str_row1col3' };
cc{3} = {'str_row3col1' 'str_row3col3' 'water_batman'};
cc{4} = {'str_row3col1' 'str_row4col2' 'helloWorld'};
cc{5} = {'str_row5_LegoMan' 'str_row5col2' 'AnotherDummyString' 'Useless String' 'BonjourWorld'};
% With a for loop, for example:
FinalCell = cell(size(cc,2),1);
for k = 1:size(cc,2)
DummyCell = cc{k}; % Use dummy cell for easier indexing
% This is where you tell Matlab what words/expressions you are looking for
A = cellfun(#isempty,regexp(cc{k},'(\w*hello|hello\w*|earth|water)','match'));
DummyCell(~A) = []; % Remove the cells containing the strings/words of interest
FinalCell{k} = DummyCell;
end
Then you're good to go. Hope that helps!
The closest thing possible I found is:
clear all
cc{1} = {'str_row1col1', 'str_row1col2' };
cc{2} = {'str_row2col1', 'bighello', 'str_row1col3' };
cc{3} = {'str_row3col1'};
cc{4} = {'str_row3col1', 'helloWorld'};
cc1 = [cc{:}];
cc1 = cc1(~strcmp('bighello',cc1));
This reorganize your array into a one dimensional array and it cannot match regular expression, but only whole words.
For a better job I am afraid you have to use for loops.

Using a string to refer to a structure array - matlab

I am trying to take the averages of a pretty large set of data, so i have created a function to do exactly that.
The data is stored in some struct1.struct2.data(:,column)
there are 4 struct1 and each of these have between 20 and 30 sub-struct2
the data that I want to average is always stored in column 7 and I want to output the average of each struct2.data(:,column) into a 2xN array/double (column 1 of this output is a reference to each sub-struct2 column 2 is the average)
The omly problem is, I can't find a way (lots and lots of reading) to point at each structure properly. I am using a string to refer to the structures, but I get error Attempt to reference field of non-structure array. So clearly it doesn't like this. Here is what I used. (excuse the inelegence)
function [avrg] = Takemean(prefix,numslits)
% place holder arrays
avs = [];
slits = [];
% iterate over the sub-struct (struct2)
for currslit=1:numslits
dataname = sprintf('%s_slit_%02d',prefix,currslit);
% slap the average and slit ID on the end
avs(end+1) = mean(prefix.dataname.data(:,7));
slits(end+1) = currslit;
end
% transpose the arrays
avs = avs';
slits = slits';
avrg = cat(2,slits,avs); % slap them together
It falls over at this line avs(end+1) = mean(prefix.dataname.data,7); because as you can see, prefix and dataname are strings. So, after hunting around I tried making these strings variables with genvarname() still no luck!
I have spent hours on what should have been 5min of coding. :'(
Edit: Oh prefix is a string e.g. 'Hs' and the structure of the structures (lol) is e.g. Hs.Hs_slit_XX.data() where XX is e.g. 01,02,...27
Edit: If I just run mean(Hs.Hs_slit_01.data(:,7)) it works fine... but then I cant iterate over all of the _slit_XX
If you simply want to iterate over the fields with the name pattern <something>_slit_<something>, you need neither the prefix string nor numslits for this. Pass the actual structure to your function, extract the desired fields and then itereate them:
function avrg = Takemean(s)
%// Extract only the "_slit_" fields
names = fieldnames(s);
names = names(~cellfun('isempty', strfind(names, '_slit_')));
%// Iterate over fields and calculate means
avrg = zeros(numel(names), 2);
for k = 1:numel(names)
avrg(k, :) = [k, mean(s.(names{k}).data(:, 7))];
end
This method uses dynamic field referencing to access fields in structs using strings.
First of all, think twice before you use string construction to access variables.
If you really really need it, here is how it can be used:
a.b=123;
s1 = 'a';
s2 = 'b';
eval([s1 '.' s2])
In your case probably something like:
Hs.Hs_slit_01.data= rand(3,7);
avs = [];
dataname = 'Hs_slit_01';
prefix = 'Hs';
eval(['avs(end+1) = mean(' prefix '.' dataname '.data(:,7))'])

Simultaneously assign values to multiple structure fields

I have a matlab structure that follows the following pattern:
S.field1.data1
...
.field1.dataN
...
.fieldM.data1
...
.fieldM.dataN
I would like to assign values to one data field (say, data3) from all fields simultaneously. That would be semantically similar to:
S.*.data3 = value
Where the wildcard "*" represents all fields (field1,...,fieldM) in the structure. Is this something that can be done without a loop in matlab?
Since field1 .. fieldM are structure arrays with identical fields, why not make a struct array for "field"? Then you can easily set all "data" members to a specific value using deal.
field(1).data1 = 1;
field(1).data2 = 2;
field(2).data1 = 3;
field(2).data2 = 4;
[field.data1] = deal(5);
disp([field.data1]);
A loop-based solution can be flexible and easily readable:
names = strtrim(cellstr( num2str((1:5)','field%d') )); %'# field1,field2,...
values = num2cell(1:5); %# any values you want
S = struct();
for i=1:numel(names)
S.(names{i}).data3 = values{i};
end
In simple cases, you could do that by converting your struct into a cell array using struct2cell(). As you have a nested structure, I don't think that will work here.
On the other side, is there any reason why your data is structured like this. Your description gives the impression that a simple MxN array or cell array would be more suitable.