I'm new to MatLab and having difficulties using the results of my functions.
My program loads a .mat file as an object, and then for each variable in the .mat, it runs an analysis. The actual analysis is done by a function called in the for loop. The results of the analysis are stored by the function in an array - or they should be! As follows:
function main()
object = matfile('data.mat')
vars = (fieldnames(object))
resultarray = zeros(length(vars))
for index = 1:length(vars)
var = vars(index)
x = object.var
resultarray = analysis(x, index)
end
end
function resultarray = analysis(x, index)
%does stuff to x
resultarray(index) = x
disp(resultarray(index))
end
The problem is - none of my variables are visible! The workspace is empty. The disp() function prints the value I assigned so I know the function is working, but how do I access resultarray after the program has finished? I have tried declaring it as a global at the beginning of main(), which doesn't seem to do anything. My array should be passed back to main() - how do I get it to save so that I can actually use the output of my function after the program has terminated?
Thanks in advance for your help.
edit - I'm aware that the scope of main() is different, but if I get rid of it I am told that "function definitions are not permitted in this context." It looks like for some reason I can't have a script and some functions which the script uses in the same file.
If you wish to keep main as a function with this syntax, then you should edit your code as follows (return resultarray from main):
function resultarray = main()
object = matfile('data.mat')
vars = (fieldnames(object))
resultarray = zeros(length(vars))
for index = 1:length(vars)
var = vars(index)
x = object.var
resultarray = analysis(x, index)
end
end
function resultarray = analysis(x, index)
%does stuff to x
resultarray(index) = x
disp(resultarray(index))
end
The problem is that the workspace has different scope than the function you have defined.
Otherwise you can create a script called, let's say main.m:
object = matfile('data.mat')
vars = (fieldnames(object))
resultarray = zeros(length(vars))
for index = 1:length(vars)
var = vars(index)
x = object.var
resultarray = analysis(x, index)
end
and create a separate file called analysis.m, which will contain the following code:
function resultarray = analysis(x, index)
%does stuff to x
resultarray(index) = x
end
Related
I try to create a class in matlab
It has a property children
properties
children
If this variable is written to - it is supposed to be an arrays of structs
it fails with
function obj = Init(obj, valueList)
%INIT Initialise with vector of new parameter sets
newSet = obj.ParamSet;
newSet.values = valueList;
obj.children(end + 1) = newSet; % <<< error
Error is :
Conversion to double from struct is not possible.
This is the struct that is used
methods(Static)
function paramset = ParamSet()
newset.('values') = [];
newset.('fitness') = 0;
paramset = newset;
end
end
The simple solution is to assign if it’s empty:
if isempty(obj.children)
obj.children = newSet;
else
obj.children(end + 1) = newSet;
end
I am working on implementing queue data structures using cell arrays in Matlab. I am trying to write functions to advance the queue by one, as well as search the queue for a specific item. At the moment the function looks like this (car types are the example data).
function q = createQueue()
q={};
q = enqueue(q,'Hilux');
q = enqueue(q,'E-Type');
q = enqueue(q,'Beetle');
q = enqueue(q,'Enzo');
q = enqueue(q,'Boxter');
q = dequeue(q)
q = searchQueue(q,'Boxter')
end
% Adds an item to the end of the queue. Returns the new queue.
function q = enqueue(q,item)
q{end+1} = item;
end
function [q item] = dequeue(q)
q{1} = {};
q{1} = q{2};
q{2} = q{3};
q{3} = q{4};
q{4} = q{5};
q{5} = {};
end
function answer = searchQueue(q, item)
for i = 1:length(q)
if q{i} == item
answer = fprintf('FOUND AT INDEX %d',i);
break
else
disp('-1')
end
end
end
Currently, the dequeue function leaves an empty cell, rather than removing the cell entirely. Is this able to be avoided? The searchQueue function also returns an error, and i am lost as to why. Thanks
Here's a rough first cut at it using matlab's object oriented capabilities. The reason for creating a class is to get reference semantics from the handle type, which allows for the dequeue/enqueue functions to modify the cell array directly, removing the need for reassignment.
I believe the code example below answers your main question about how to dequeue without leaving an empty cell (could be used without the OOP approach to the same effect).
To answer your question about what's wrong with your search: 1) the comparison q{i} == item gives you problems because == compares characters (which fails if there is a string size mismatch) whereas you wanted to use isequal(); 2) you wanted sprintf rather than fprintf; and 3) while not strictly wrong, the else in your loop happens on every item that doesn't match, which is probably not what you wanted.
classdef Queue < handle
properties
data = {}
end
methods
function q = Queue()
% TODO: do something in constructor if desired
end
function item = dequeue(q)
% TODO: bounds check
item = q.data(1);
q.data = q.data(2:end);
end
function enqueue(q,item)
q.data{end+1} = item;
end
function answer = search(q, item)
% TODO: check for multiple occurrences
answer = 'NOT FOUND';
for i = 1:length(q.data)
if isequal(q.data{i},item)
answer = sprintf('FOUND AT INDEX %d',i);
break
end
end
end
end
end
I have a function but I cannot deal with the variable named data when I call the function. If I run the code alone (without calling the function, it works).
Please find the actual code below:
function data = returns_ext(input);
clear all
clc
ticker = 'BA';
filename = ['C:\Users\FP\Documents\MatlabCode\P\prices\' ticker 'daily.csv'];
newData1 = importdata(filename);
% Create new variables in the base workspace from those fields.
vars = fieldnames(newData1);
for i = 1:length(vars)
assignin('base', vars{i}, newData1.(vars{i}));
end
prices_data = data;
ERROR: At compilation, "data" was determined to be a variable and this
variable is uninitialized. "data" is also a function name and previous versions of MATLAB would have
called the function.
However, MATLAB 7 forbids the use of the same name in the same
context as both a function and a variable.
Error in ==> returns_ext at 17
prices_data = data;
You should replace assignin by eval, since assignin assigns either in the caller function calling returns_ext or the base workspace. See the simple example below:
function test
newData1.prices = 1;
newData1.dates = 2;
variables = {'prices','dates'};
for i = 1:length(variables)
temp = newData1.(variables{i});
eval([variables{i} ' = temp;']);
end
disp(prices)
disp(dates)
If the data is available in 'base' workspace then you need to update your code as this:
data = eval('base','data;');
prices_data = data;
I have function f1 which must contain subfunctions, so I can't use another script:
function vars = f1()
a = 1;
b = 'hello';
c = {[1 2 3]};
currvars = whos; %all variable info
for k = 1:size(currvars, 1)
eval(['vars.(currvars(k).name) = ' currvars(k).name ';']);
end
end
I call the function in a script, and then I create the variables in the script using genvarname() and eval():
vars = f1();
varnames = genvarname(fieldnames(vars));
for k = 1:size(varnames(:),1) %Creates vars with the struct's fieldnames.
eval([varnames{k} ' = vars.' varnames{k} ';']);
end
clearvars vars varnames
I'd like to fit the variable creation process into a function somehow while reading out all the variables only to the script calling it, but I don't want to assign a hundred different variable names to the output. Does anyone have any advice on how to do this?
DON'T CREATE zillions of automatically named variables. This is foolish and terribly poor programming style. Instead, learn to use arrays. Multidimensional arrays, cell arrays, struct arrays.
Or, do what you have done, and then be forced to find a kludge like you are looking for.
Take your pick. Eval is evil.
You could return a structure with "corrected" fieldnames:
function output = someFunc
vars = f1();
protected = { %# some list of varnames you don't want
};
names = fieldnames(vars);
newnames = genvarname(names, protected);
for k = 1:numel(newnames)
output.(newnames{k}) = vars.(names{k});
end
end
If you then use
output = someFunc;
varnames = fieldnames(output);
for k = 1:numel(fieldnames)
eval([varnames{k} ' = output.' varnames{k} ';']);
end
in the script/function where you want the variable names, you have a relatively clean way of locking everything up in the function someFunc without having to pre-define all output variable names.
You can also do this in one step:
function someFunc2
vars = f1();
protected = { %# some list of varnames you don't want
};
names = fieldnames(vars);
newnames = genvarname(names, protected);
for k = 1:numel(newnames)
assignin('caller', newnames{k}, vars.(names{k}));
end
end
Which means you just call the function
someFunc2;
in your script, and the function then defines and assigns all the variables in the script's workspace.
A tiny step forward, but forward nonetheless :)
CREDIT TO RODY...
#Old semi-"global" variables:
function vars = f1()
a = 1;
b = 'hello';
c = {[1 2 3]};
currvars = whos; %all variable info
for k = 1:size(currvars, 1)
eval(['vars.(currvars(k).name) = ' currvars(k).name ';']);
end
end
#Function to assign variables to the calling script's/function's workspace. Variable names are determined by the single structure's fieldnames:
function setvars(func)
vars = func;
protected = {'If needed, put variable names you do not want here'};
names = fieldnames(vars);
newnames = genvarname(names, protected);
for k = 1:numel(newnames)
assignin('caller', newnames{k}, vars.(names{k}));
end
end
#Script call:
setvars(f1);
I have a constructor like this:
function p = class_name(folder, file_name)
xmlfile = fullfile(folder, file_name);
xDoc = xmlread(xmlfile);
struct = xml2struct(xDoc);
%lots of repetitive code
end
It reads and XML file and transforms it into a struct. The struct elements are then assign to the class's properties/fields using some repetitive code like this:
if(isfield(struct.parameters, 'parameter_name'))
p.property_name = struct.parameters.parameter_name.Text;
else
p.property_name = '';
end
I would like to put this into a method/function which, given the name of the struct element (here 'parameter_name') and the name of the class field/property (here 'property_name') assigns the former to the latter.
Is it possible to write a generic function/method for this? Thanks.
You can implement such a function using dynamic field names. This is the recommended implementation for such cases:
function p = setparam(s, p, param_name, prop_name)
if(isfield(s.parameters, param_name))
param = s.parameters.(param_name);
p.(prop_name) = param.Text;
else
p.(prop_name) = '';
end
end
You can also use setfield and getfield on older versions of MATLAB:
function p = setparam(s, p, param_name, prop_name)
if(isfield(s.parameters, param_name))
param = getfield(s.parameters, param_name);
p = setfield(p, prop_name, getfield(param, 'Text'));
else
p = setfield(p, prop_name, '');
end
end
Do not use struct for structure name in your code - it is a reserved keyword.
Use dynamic field names:
yourStruct.parameters.('parameter_name')
Here is a a generic function:
Can be used for either structs or class objects
function obj_to = set_props(obj_to, obj_from)
% insert properties from obj_from into obj_to.
props_from = fieldnames(obj_from);
props_to = fieldnames(obj_to);
for k = 1 : length(props_to)
if ismember(props_to{k}, props_from)
obj_to.(props_to{k}) = obj_from.(props_to{k});
else
obj_to.(props_to{k}) = '';
end
end
Now, in the constructor:
function obj = class_name(folder, file_name)
xmlfile = fullfile(folder, file_name);
xDoc = xmlread(xmlfile);
s = xml2struct(xDoc); % do not use word "struct" for variables
set_props(obj, s); % if obj has handle, no need to return it from set_props()
end