MATLAB: Using the If statement with a string to return values from other arrays - matlab

I have a matlab program where I am importing some arrays from excel. I am trying to write an if statement that looks in the first array, say:
Thing-1 Thing-1 Thing-3 Thing-5
If a column is a "Thing-1", then it goes to a different array, and calculates 3 values that are to be given different variable names...any guidance would be much appreciated! Thanks!

You need a function like vlookup as in Excel.
I have written one. Here is the source code:
function [content, index] = vlookup(m, e, column, lookcolumn)
if isempty(m) || isempty(e), return; end
if nargin <= 3, lookcolumn = 1; end
isechar = ischar(e);
assert(isechar || isnumeric(e), 'the second parameter must be a string or numeric');
if iscell(m)
content = {}; index = [];
if isechar
index = find(strcmp(e, m(:, lookcolumn)));
content = m(index, column);
else
for i = 1:size(m, 1)
if isnumeric(m{i, lookcolumn}) && m{i, lookcolumn} == e
content = [content; m(i, column)]; %#ok<*AGROW>
index = [index; i];
end
end
end
else
assert(~isechar, 'When the first para is a matrix, the second para must be numeric');
index = find(m(:, lookcolumn) == e);
content = m(index, column);
end

The question is... not very clear, but let me try and give you some suggestions.
Say you read some data from an Excel workbook in which the first row is headers, followed by lots of rows with numbers.
[num,txt] = xlsread(excelFileName);
so that num contains the numeric data and txt the string column headers.
Then you can check for the string Thing-1 in the column headers. thingOneIdx is an array with indices into the columns of the header. In your example, it would be [1 2], since the first two columns are Thing-1.
thingOneIdx = find(strcmp('Thing-1',txt));
You can create three cell arrays, firstValue, secondValue, and thirdValue that will store the results of the three calculations. If you need to keep the Thing-1 data around in an additional array, you can do that analogously.
%# define cell arrays (do it in one go using deal)
[firstValue,secondValue,thirdValue] = deal(cell(length(thingOneIdx),1));
%# for simplicity and readability, loop through isThingOneIdx to assign data
for ct = 1:length(thingOneIdx)
myIdx = thingOneIdx(ct);
firstValue{ct} = someCalculation(num(myIdx,:));
secondValue{ct} = someOtherCalculation(num(myIdx,:));
%# etc
end

Related

What is the best practice to recursively extract data from a nested structure in matlab?

I'm trying to exctract some data from a nested structure in a recursive manner. First, I know that this has a field (values) which repeats itself inside the nested structure. Secondly I know that the structure which has those values has only structures as fields. In the below code I've tried to acces the structure.values by searching if my current structure has a field named values. If it has, I put .values at the end of my structure name. If it doesn't have this field, I verify if all the fields are structures. If they are, it means that I will have to consider them further and to extract the values from each one. If the fields are not structures, it means that they are values and I save them into a new simplified structure. Example of fields that I want: S.values.model1.values.mission.values.(alt/list). Currently, with the below code I'm only able to get the values from one field and then I get an error and don't know how to approach further.
Code example:
clear all
clc
S=struct()
S.case='1';
S.type='A';
S.values.model1.case='2'
S.values.model1.type='C'
S.values.model1.values.mission.case='3'
S.values.model1.values.mission.type='D'
S.values.model1.values.mission.values.alt='none'
S.values.model1.values.mission.values.list=2
S.values.model1.values.mission.values.parameter=4
S.values.model1.values.phase.case='4'
S.values.model1.values.phase.type='A'
S.values.model1.values.phase.values.num='all'
S.values.model1.values.phase.values.eq=2
S.values.model1.values.phase.values.unit=4
S.values.model1.values.analysis.case='1'
S.values.model1.values.phase.type='A'
S.values.model1.values.phase.values.nump1.list='all'
S.values.model1.values.phase.values.nump1.table='four'
S.values.model1.values.phase.values.nump1.mean=0
S.values.model1.values.phase.values.nump2.list='none'
S.values.model1.values.phase.values.nump2.table='three';
S.values.model1.values.phase.values.nump2.mean=1
s=S.values.model1;
names=fieldnames(s);
nnames=numel(names);
newStruct={};
[valsi,newstructi]=extractValues(names,s,nnames,newStruct)
function [vals,newStruct]=extractValues(names,vals,nnames,newStruct)
if any(strcmp(names,'values'))
vals=vals.('values');
names=fieldnames(vals)
nnames=numel(names)
[vals,newStruct]=extractValues(names,vals,nnames,newStruct);
end
for j=1:nnames
value(j)=isstruct((vals.(names{j})));
end
if all(value)
for k=1:nnames
vals=(vals.(names{k}));
names=fieldnames(vals);
nnames=numel(names);
[vals,newStruct]=extractValues(names,vals,nnames,newStruct);
end
else
for j=1:nnames
value=(vals.(names{j}));
newStruct.(names{j})=value;
end
end
end
As it is known beforehand what fields are requested you can arrange the subsequent filed names in a cell array and use a loop to extract the value:
names = {'values', 'model1', 'values', 'mission', 'values', 'alt'};
out = S;
for name : names
out = out.(name{1});
end
So that is a loop version of using:
out = S.values.model1.values.mission.values.alt;
EDIT:
If you want to list all field names and all field values you can used these functions:
function out = names(s, p)
if isstruct(s)
out = {};
f = fieldnames(s);
for i = 1:numel(f)
s1 = s.(f{i});
p1 = [p '.' f{i}];
out = [out; names(s1, p1)];
end
else
out = {p};
end
end
function out = values(s)
if isstruct(s)
out = {};
f = fieldnames(s);
for i = 1:numel(f)
out = [out; values(s.(f{i}))];
end
else
out = {s};
end
end
Use them as:
n = names(S, 'S');
v = values(S);

How to use for loop to add the previous values in an array in MATLAB?

I have an array like t. It contains the numbers and I would like to add to each number the previous ones. For example: t=[0,2,3,5] and I would like to get tnew=[0,2,5,10]. I tried out this code but it is wrong for sure. (There are 5292 values)
for i=0:5292
t(i)=t(i)+t(i+1)
end
For some array t = [0,2,3,5];, you can just do tnew = cumsum(t).
If you really want to do this in a loop, you need to start from the 2nd index, and keep adding to the value from the previous index
t = [0,2,3,5];
tnew = t;
for ii = 2:numel(t)
tnew(ii) = t(ii) + tnew(ii-1);
end

How to extract file names in a loop into a character array?

I have a code like below. I want to generate an array with all the file names and combine with the data that I collected from each file.
DataCC = dir('*-CC.xls'); %select the file type
MeanAreaCC=[];
PlateNameCC=[];
for w = 1: numel(DataCC)
basefilenamedata=DataCC(w).name; %extract the file name
T=readtable(basefilenamedata); %read table in
PlateNameCC=[PlateNameCC basefilenamedata]; %generate the file name array
MeanAreaCC = [MeanAreaCC mean(T.Area)]; %generate the data array
end
x=array2table([PlateNameCC, transpose(MeanAreaCC)],'VariableNames',{'Iso-Condi-Rep','MeanAreaCC'}); %combine two arrays just generated
writetable(x,fullfile(DataFolder,'DataSummary.xls'),'Sheet',1,'Range','A1');
But my code didn't work, as the PlateNameCC is generated as one character but not an array. This came to an error complaining different array size, when I combine PlateNameCC with MeanAreaCC. Could somebody check it for me? Thank you!
There are a couple things wrong here.
First, PlateNameCC = [PlateNameCC basefilenamedata]; is going to create one long string of garbage.
For example:
fnames = dir('*.m')
namelist = [];
for ii = 1:numel(fnames)
namelist = [namelist fnames(ii).name]
end
Gives me:
namelist =
'SOcode.mcallbacksclass.mtestcode.m'
You want to use a string array or a cell array:
fnames = dir('*.m');
namelist1 = string({fnames.name});
namelist2 = {fnames.name};
Which returns:
namelist1 =
1×3 string array
"SOcode.m" "callbacksclass.m" "testcode.m"
namelist2 =
1×3 cell array
{'SOcode.m'} {'callbacksclass.m'} {'testcode.m'}
Second, there's no point trying to concatenate two (very) unlike arrays to create a table when you can just use the table constructor itself:
fnames = dir('*.m');
namelist = string({fnames.name});
data = [1, 2, 3];
T = table(namelist.', data.');
Which gives:
T =
3×2 table
Var1 Var2
__________________ ____
"SOcode.m" 1
"callbacksclass.m" 2
"testcode.m" 3

Struggling to vertically append a string ( csv file) to an existing matrix in Scilab/matlab

M=read_csv("Gradesheets\MECN2073_2014.csv")
disp(size(M,1))
for x=1:1:size(M,1)
StudNum=M(x,1)
Grd=M(x,2) // Grd is grade column in gradesheets hence x,2 (column 2 of Grd )
if find(StudNum==StudentNumbers)>0 then disp("Exists")
H = [StudNum]
StudentNumbers = [StudentNumbers;StudNum]
end
end
This is where i get error:
Undefined operation for the given operands.
check or define function %s_f_c for overloading.
at line 38 of exec file called by :
I assume that StudentNumbers is the vector containing all your existing students right? If so, try the code below and let me know what you get.
M=read_csv("Gradesheets\MECN2073_2014.csv")
storing = [];
for i=1:size(M,1)
StudNum=M(i,1)
if find(StudNum==StudentNumbers(i)) == 1
disp("Exists");
storing = [storing;StudNum];
end
end

How do I iterate through an imported excel doc?

what I need to do for this code is import a giant (302x11) excel doc, and then ask the user for an input. Then, I need to iterate through each element in the 5th column of the excel array, and if that element matches the user input, save the entire row to a new array. After going through all 302 rows, I need to display the new array.
So far, I have this:
Vin = input('Vin: ');
filename='MagneticCore.xlsx';
sheet=2;
xlRange='B2:L305';
[ndata, text, alldata] = xlsread(filename,sheet,xlRange,'basic');
After this, I'm not sure how to iterate through the alldata array.
alldata is a cell, to select the fifth column you can use alldata{:,5}. Searching in Cells is done this way without iterating
Try it on your own, if you get stuck update your question with code and error message
Daniel R is right, you can do this without iterating through the cell array. Here's how you could iterate through the array if you needed to:
[ndata, text, alldata] = xlsread('Book1.xlsx');
target = 12;
newArray = {};
for r = 1:size(alldata, 1)
% get the element in the fifth column of the current row
e = raw{r,5};
if e == target
% add to newArray
newArray{end + 1} = alldata(r,:);
end
end
% display newArray
for r = 1:size(newArray, 1)
disp(newArray{r})
end