How do I run a foreach field in a class/ struct in matlab? - class

This is my class : (direction) :
classdef direction
properties
up = zeros(4,5)
down = zeros(4,5)
left = zeros(4,5)
right = zeros(4,5)
end
%%%
methods
end
end
I want to be able to run a
for each field in 'direction'
do something
but I don't know how to use it.
Now I'm using
ROAD.up = ...
but I'll want more fields at the end (16 or 32)
I try now a struct solution :
I'm using at the moment at
road(1).direction
and etc
but I find the class solution more right...

My first guess is you might be interested in structfun
Theoretically it should work with classes as well - practically I find matlab classes unpredictable.

Get the properties and loop over them:
d = direction
p = properties(d)
for k = 1:length(p)
prop = p{k};
d.(prop) = k
end
For example, the above code would start with:
d =
direction
Properties:
up: [4x5 double]
down: [4x5 double]
left: [4x5 double]
right: [4x5 double]
and result in:
d =
direction
Properties:
up: 1
down: 2
left: 3
right: 4
If you want to specify the list yourself, you can use a cell array of strings and use the obj.('name') operator:
p = {'up', 'down', 'left', 'right'};
k = 2; % Have a loop here instead
d.(p{k}) = 5; % Set property value

You can roll your own function that applies functions to object fields, analagous to structfun.
function out = objfieldfun(x, fcn)
%OBJFIELDFUN Apply a function to every field of an object
out = x;
fields = fieldnames(x);
for iX = 1:numel(x)
for iField = 1:numel(fields)
out(iX).(fields{iField}) = feval(fcn, x(iX).(fields{iField}));
end
end
Then you can use it like this.
d = direction;
d2 = objfieldfun(d, #(x)x+2);
But... usually objects' named properties have particular meanings and roles, and it'd be unusual to apply the same operation to all fields. Maybe it would make more sense to stash the similar properties inside a struct which itself is in a field on the object.

Related

flatten a struct of arbitrarily nested arrays of integers into a flat array of integers

Is it possible to flatten an array of arbitrarily nested arrays of integers into a flat array of integers in Matlab? For example,
[[1,2,[3]],4] -> [1,2,3,4]
Any kind of guidance will be helpful. Thanks.
For example,
a.c = [5,4];
a.b.a=[9];
a.b.d=[1,2];
a= b: [1x1 struct]
c: [5 4]
In this case, my output will be
output= [9,1,2,5,4]
I think you will have to adapt the flatten function from the file exchange to use struct2cell so something like this:
function C = flatten_struct(A)
A = struct2cell(A);
C = [];
for i=1:numel(A)
if(isstruct(A{i}))
C = [C,flatten_struct(A{i})];
else
C = [C,A{i}];
end
end
end
This results in:
a.c = [5,4];
a.b.a=[9];
a.b.d=[1,2];
flatten_struct(a)
ans =
5 4 9 1 2
So the order is in the order you declared your struct instead of in your example order which I presume is alphabetical. But you have control over this so it shouldn't be a problem.
I have a preliminary hack which does work but rather clumsily. It descends recursively, saving structure names and unpacking the returned structure at each "level" .
% struct2sims converter
function simout = struct2sims(structin)
fnam = fieldnames(structin);
for jf = 1:numel(fnam)
subnam = [inputname(1),'_',fnam{jf}];
if isstruct(structin.(fnam{jf}) ) ,
% need to dive; build a new variable that's not a substruct
eval(sprintf('%s = structin.(fnam{jf});', fnam{jf}));
eval(sprintf('simtmp = struct2sims(%s);',fnam{jf}) );
% try removing the struct before getting any farther...
simout.(subnam) = simtmp;
else
% at bottom, ok
simout.(subnam) = structin.(fnam{jf});
end
end
% need to unpack structs here, after each level of recursion
% returns...
subfnam = fieldnames(simout);
for kf = 1:numel(subfnam)
if isstruct(simout.(subfnam{kf}) ),
subsubnam = fieldnames(simout.(subfnam{kf}));
for fk = 1:numel(subsubnam)
simout.([inputname(1),'_',subsubnam{fk}])...
= simout.(subfnam{kf}).(subsubnam{fk}) ;
end
simout = rmfield(simout,subfnam{kf});
end
end
% if desired write to file with:
% save('flattened','-struct','simout');
end

Matlab loop through functions using an array in a for loop

I am writing a code to do some very simple descriptive statistics, but I found myself being very repetitive with my syntax.
I know there's a way to shorten this code and make it more elegant and time efficient with something like a for-loop, but I am not quite keen enough in coding (yet) to know how to do this...
I have three variables, or groups (All data, condition 1, and condition 2). I also have 8 matlab functions that I need to perform on each of the three groups (e.g mean, median). I am saving all of the data in a table where each column corresponds to one of the functions (e.g. mean) and each row is that function performed on the correspnding group (e.g. (1,1) is mean of 'all data', (2,1) is mean of 'cond 1', and (3,1) is mean of 'cond 2'). It is important to preserve this structure as I am outputting to a csv file that I can open in excel. The columns, again, are labeled according the function, and the rows are ordered by 1) all data 2) cond 1, and 3) cond 2.
The data I am working with is in the second column of these matrices, by the way.
So here is the tedious way I am accomplishing this:
x = cell(3,8);
x{1,1} = mean(alldata(:,2));
x{2,1} = mean(cond1data(:,2));
x{3,1} = mean(cond2data(:,2));
x{1,2} = median(alldata(:,2));
x{2,2} = median(cond1data(:,2));
x{3,2} = median(cond2data(:,2));
x{1,3} = std(alldata(:,2));
x{2,3} = std(cond1data(:,2));
x{3,3} = std(cond2data(:,2));
x{1,4} = var(alldata(:,2)); % variance
x{2,4} = var(cond1data(:,2));
x{3,4} = var(cond2data(:,2));
x{1,5} = range(alldata(:,2));
x{2,5} = range(cond1data(:,2));
x{3,5} = range(cond2data(:,2));
x{1,6} = iqr(alldata(:,2)); % inter quartile range
x{2,6} = iqr(cond1data(:,2));
x{3,6} = iqr(cond2data(:,2));
x{1,7} = skewness(alldata(:,2));
x{2,7} = skewness(cond1data(:,2));
x{3,7} = skewness(cond2data(:,2));
x{1,8} = kurtosis(alldata(:,2));
x{2,8} = kurtosis(cond1data(:,2));
x{3,8} = kurtosis(cond2data(:,2));
% write output to .csv file using cell to table conversion
T = cell2table(x, 'VariableNames',{'mean', 'median', 'stddev', 'variance', 'range', 'IQR', 'skewness', 'kurtosis'});
writetable(T,'descriptivestats.csv')
I know there is a way to loop through this stuff and get the same output in a much shorter code. I tried to write a for-loop but I am just confusing myself and not sure how to do this. I'll include it anyway so maybe you can get an idea of what I'm trying to do.
x = cell(3,8);
data = [alldata, cond2data, cond2data];
dfunction = ['mean', 'median', 'std', 'var', 'range', 'iqr', 'skewness', 'kurtosis'];
for i = 1:8,
for y = 1:3
x{y,i} = dfucntion(i)(data(1)(:,2));
x{y+1,i} = dfunction(i)(data(2)(:,2));
x{y+2,i} = dfunction(i)(data(3)(:,2));
end
end
T = cell2table(x, 'VariableNames',{'mean', 'median', 'stddev', 'variance', 'range', 'IQR', 'skewness', 'kurtosis'});
writetable(T,'descriptivestats.csv')
Any ideas on how to make this work??
You want to use a cell array of function handles. The easiest way to do that is to use the # operator, as in
dfunctions = {#mean, #median, #std, #var, #range, #iqr, #skewness, #kurtosis};
Also, you want to combine your three data variables into one variable, to make it easier to iterate over them. There are two choices I can see. If your data variables are all M-by-2 in dimension, you could concatenate them into a M-by-2-by-3 three-dimensional array. You could do that with
data = cat(3, alldata, cond1data, cond2data);
The indexing expression into data that retrieves the values you want would be data(:, 2, y). That said, I think this approach would have to copy a lot of data around and probably isn't the best for performance. The other way to combine data together is in 1-by-3 cell array, like this:
data = {alldata, cond1data, cond2data};
The indexing expression into data that retrieves the values you want in this case would be data{y}(:, 2).
Since you are looping from y == 1 to y == 3, you only need one line in your inner loop body, not three.
for y = 1:3
x{y, i} = dfunctions{i}(data{y}(:,2));
end
Finally, to get the cell array of strings containing function names to pass to cell2table, you can use cellfun to apply func2str to each element of dfunctions:
funcnames = cellfun(#func2str, dfunctions, 'UniformOutput', false);
The final version looks like this:
dfunctions = {#mean, #median, #std, #var, #range, #iqr, #skewness, #kurtosis};
data = {alldata, cond1data, cond2data};
x = cell(length(data), length(dfunctions));
for i = 1:length(dfunctions)
for y = 1:length(data)
x{y, i} = dfunctions{i}(data{y}(:,2));
end
end
funcnames = cellfun(#func2str, dfunctions, 'UniformOutput', false);
T = cell2table(x, 'VariableNames', funcnames);
writetable(T,'descriptivestats.csv');
You can create a cell array of functions using str2func :
function_string = {'mean', 'median', 'std', 'var', 'range', 'iqr', 'skewness', 'kurtosis'};
dfunction = {};
for ii = 1:length(function_string)
fun{ii} = str2func(function_string{ii})
end
Then you can use it on your data as you'd like to :
for ii = 1:8,
for y = 1:3
x{y,i} = dfucntion{ii}(data(1)(:,2));
x{y+1,i} = dfunction{ii}(data(2)(:,2));
x{y+2,i} = dfunction{ii}(data(3)(:,2));
end
end

Using MATLAB dot notation to set multiple properties at once

Recently MATLAB enabled handles to plots to use dot notation to set properties.
e.g.
set(plotLeft,'marker','o');
can now be
plotLeft(1).Marker = 'o';
Is it possible to use this new dot notation to set multiple fields at once. Some code below for an example:
clc; clear all;
x = logspace(-3,0,100)';
plot1 = sin(x);
plot2 = cos(x);
[hax,plotLeft,plotRight] = plotyy(x,[plot1 plot1],x,[plot2 plot2])
plotLeft(1).Marker = 'o';
plotLeft(2).Marker = 'x';
I would like to set this bit:
plotLeft(1).Marker = 'o';
plotLeft(2).Marker = 'x';
But in one line. I can access the marker types by:
plotLeft([1 2]).Marker
But it will not let me set them how I think it would work:
>> plotLeft([1 2]).Marker = ['o' 'x']
Insufficient number of outputs from function on right hand side of equal sign to
satisfy overloaded assignment.
You can use deal function to achieve this:
[plotLeft([1 2]).Marker] = deal('o', 'x');
plotLeft([1 2]).Marker creates a comma-separated list so you cannot assign to it directly, but you can use deal to handle it, it will be equivalent of this:
[plotLeft(1).Marker, plotLeft(2).Marker] = deal('o', 'x');

MATLAB QUESTIONS on logical indexing and cell2struct function

First Question:
Hello there!
I am trying to assign this vector
v(mod(v,2)~=0)=0
The operations is supposed to replace odd numbers in a vector with 0. I am trying to assign this vector to result variable in a function.
something goes wrong when I try this
function
function [result1,result2] = myfunction(v)
v(mod(v,2)==0)= 0;
result1 = v;
v(mod(v,2)~=0) = 0;
result2 = v;
return
QUESTION 2:
I am trying to figure out an alternative way to express the the function cell2struct in for-loop format
for example,
if we have a cell array with 2 dimensions containing food labels. Their names, caloric count and price, each in one column. Can we write a function that's can transfer the information in cells to a struct that contain each of the fields above?
Thanks
Question #1
You are setting all even numbers to 0, but then you are using this mutated result to search for odd numbers and setting them to 0. This will probably not give you what you intended as you are using a modified copy of the original vector, so it would be prudent that you keep a copy of the vector before doing each operation.
function [result1,result2] = myfunction(v)
vcopy = v; %// Make a copy
vcopy(mod(vcopy,2)==0)= 0; %// Find even numbers and set to 0
result1 = vcopy;
vcopy = v; %// Make another copy
vcopy(mod(vcopy,2)~=0) = 0; %// Find odd numbers and set them to 0.
result2 = vcopy;
return
Question #2
Yup. If you have a list of field names stored in f and their corresponding entities for each field stored in c, simply use a loop like so:
function [s] = my_cell2struct(c, f)
for idx = 1 : numel(f)
s.(f{idx}) = c{idx};
end
The above code does no error checking, so you need to make sure that the total number of elements in c matches those of f. Also, c and f must be cell arrays. Notice that s wasn't declared at all in the function. Also, using the dot operator combined with enclosing brackets and a string that goes inside the enclosing brackets allows you to dynamically create field names on the fly. As such, for each string in f, we access the corresponding value stored in c, and we create a field name that contains this value.
Here's a reproducible example from the MathWorks documentation:
c = {'tree',37.4,'birch'};
f = {'category','height','name'};
s = cell2struct(c, f, 2)
s =
category: 'tree'
height: 37.4000
name: 'birch'
Notice that I use cell2struct here from native MATLAB to produce the above structure. Doing the above for loop which is wrapped in a function called my_cell2struct, we get:
c = {'tree',37.4,'birch'};
f = {'category','height','name'};
s = my_cell2struct(c, f)
s =
category: 'tree'
height: 37.4000
name: 'birch'

Is there a 'self' to refer own struct in MATLAB?

I'm grouping a set of anonymous functions into a structure and some variables within that structure. Is there a way to refer 'self', i.e, own structure? What I'd like to accomplish is to have a function returns some values based on the member variables. For simplicity, say I have a struct a, where
a.value_1 = 3;
a.value_2 = 2;
a.sum = #()(self.value_1 + self.value_2)
Is there something like that possible in MATLAB?
Before objected-oriented programming was introduced in MATLAB (including both classdef-style and the obsolete #-directory style classes), one could create lightweight objects using closures and nested functions (lacking inheritance of course). This concept also exists in other languages.
Here is an example:
function s = mystruct()
s = struct('value_1',[], 'value_2',2, 'sum',#mysum);
s.value_1 = 3;
function out = mysum()
out = s.value_1 + s.value_2;
end
end
Which is used as:
>> s = mystruct()
s =
value_1: 3
value_2: 2
sum: #mystruct/mysum
>> s.value_1 = 10; % NOTE: this wont do what you expect!
>> s.sum()
ans =
5
Note that variables are immediately captured when creating a closure (functions have their own private copy if you will). So if you change one of the exposed fields from the returned structure, it will not be reflected in the enclosed state (think of them as read-only properties).
One solution is to provide accessor methods:
function obj = mystruct()
% think of those as private properties
value_1 = 3;
value_2 = 2;
% returned object (this or self)
obj = struct();
% public accessors for properties
obj.value_1 = #accessValue1;
function out = accessValue1(in)
if nargin > 0, value_1 = in; end
out = value_1;
end
obj.value_2 = #accessValue2;
function out = accessValue2(in)
if nargin > 0, value_2 = in; end
out = value_2;
end
% member method
obj.sum = #mysum;
function out = mysum()
out = value_1 + value_2;
end
end
So now we could say:
>> s = mystruct()
s =
value_1: #mystruct/accessValue1
value_2: #mystruct/accessValue1
sum: #mystruct/mysum
>> x = s.value_1(); % get
>> s.value_1(10); % set
>> s.sum()
ans =
12
Which is starting to look like the current recommended approach to create classes:
classdef mystruct < handle
properties
value_1 = 3;
value_2 = 2;
end
methods
function out = sum(obj)
out = obj.value_1 + obj.value_2;
end
end
end
Used in a similar manner:
>> s = mystruct()
s =
mystruct with properties:
value_1: 3
value_2: 2
>> s.value_1 = 10;
>> s.sum
ans =
12
We could also define get/set access methods as before..
This seems to work but I think you should rather create a class than a struct to do this:
a.value_1 = 3;
a.value_2 = 2;
a.sum = #(x)(x.value_1 + x.value_2)
a.sum(a)
With this change
a.value_1 = 3;
a.value_2 = 2;
a.sum = #()(a.value_1 + a.value_2)
Then a.sum() returns 5. But what happens when you change one of the values, later on, e.g., set a.value_1 = 5? Now a.sum() returns ... still 5. The parameters passed into the anonymous function are evaluated upon instantiation. If you want the second behavior to work properly you need to use a class. See my answer to this question for more. The only reason to use a function handle like you have is to avoid evaluating and storing a large output of a function until it's needed.