How do I copy fields names and their contents to another struct variable in matlab - matlab

Lets say that I have this code:
a=struct;
a(1).a='a1';
a(1).b='b1';
a(1).c='c1';
a(2).d='a1';
a(2).e='b1';
a(2).f='c1';
a(3).g='a1';
a(3).h='b1';
a(3).i='c1';
Now, I want to copy only a(2) to b(1) with its all fields, but I don't know what fields are in a. for example:
b=struct;
b(1)=a(2);
b(2)=a(3);
(if I do that I get the error:
'Subscripted assignment between dissimilar structures.')
How can I do that?

Let s1 be the input struct and s2 be the desired output struct. Here's one approach based on struct2cell and cell2struct to get s2 -
%// Given input struct
s1=struct;
s1(1).a='A';
s1(1).b='B';
s1(1).c='C';
s1(2).d='D';
s1(2).e='E';
s1(2).f='F';
s1(3).g='G';
s1(3).h='H';
s1(3).i='I';
idx = [2 3]; %// indices of struct data to be copied over from s1 to s2
fn = fieldnames(s1) %// get fieldnames
s1c = struct2cell(s1) %// Convert s1 to its cell array equivalent
%// Row indices for the cell array that has non-empty cells for the given idx
valid_rowidx = ~all(cellfun('isempty',s1c(:,:,idx)),3)
%// Construct output struct
s2 = cell2struct(s1c(valid_rowidx,:,idx),fn(valid_rowidx))
Thus, you would end up with the output -
s2 =
1x2 struct array with fields:
d
e
f
g
h
i
Finally, you can verify the contents of the output struct like so -
%// Verify results
check1 = [s1(2).d s1(2).e s1(2).f]
check2 = [s2(1).d s2(1).e s2(1).f]
check3 = [s1(3).g s1(3).h s1(3).i]
check4 = [s2(2).g s2(2).h s2(2).i]
which yields -
check1 =
DEF
check2 =
DEF
check3 =
GHI
check4 =
GHI

Don't declare b. Then use deal:
a=struct;
a(1).a='a1';
a(1).b='b1';
a(1).c='c1';
a(2).d='a1';
a(2).e='b1';
a(2).f='c1';
a(3).g='a1';
a(3).h='b1';
a(3).i='c1';
b(1) = deal(a(2));
b(2) = deal(a(3));
If you declare b before using deal, you will have to declare b as a struct with all fields which a has. In this case you don't need 'deal' anymore, just assign them normally as you did.

Related

Fibonacci Function in MATLAB

I am attempting to create a function for the Fibonacci numbers using a for loop. My code is as follows:
function fib = fibGenerator(N)
fib(1) = 0;
fib(2) = 1;
for i = 3:N
fib(i) = fib(i-1)+fib(i-2);
end
The following error message is displayed: Variable fib must be of data type uint32. It is currently of type double. Check where the variable is assigned a value.
I'm unsure of how to correct this.
Update
function fib = fibGenerator(N)
fibGenerator(1) = uint32(0);
fibGenerator(2) = uint32(1);
for i = 3:N
fibGenerator(i) = fibGenerator(i-1)+fibGenerator(i-2);
end
You have to cast when you initially create fib: fib(1) = uint32(0);
Here is an example demonstrating this. When creating x you decide the type. Even if later assignments are double or of other types, it will keep its type.
>> x=uint32(1)
x =
uint32
1
>> x(2)=double(2)
x =
1×2 uint32 row vector
1 2

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

For loop for storing value in many different matrix

I have written a code that stores data in a matrix, but I want to shorten it so it iterates over itself.
The number of matrices created is the known variable. If it was 3, the code would be:
for i = 1:31
if idx(i) == 1
C1 = [C1; Output2(i,:)];
end
if idx(i) == 2
C2 = [C2; Output2(i,:)];
end
if idx(i) == 3
C3 = [C3; Output2(i,:)];
end
end
If I understand correctly, you want to extract rows from Output2 into new variables based on idx values? If so, you can do as follows:
Output2 = rand(5, 10); % example
idx = [1,1,2,2,3];
% get rows from Output which numbers correspond to those in idx with given value
C1 = Output2(find(idx==1),:);
C2 = Output2(find(idx==2),:);
C3 = Output2(find(idx==3),:);
Similar to Marcin i have another solution. Here i predefine my_C as a cell array. Output2 and idx are random generated and instead of find i just use logical adressing. You have to convert the data to type cell {}
Output2 = round(rand(31,15)*10);
idx = uint8(round(1+rand(1,31)*2));
my_C = cell(1,3);
my_C(1,1) = {Output2(idx==1,:)};
my_C(1,2) = {Output2(idx==2,:)};
my_C(1,3) = {Output2(idx==3,:)};
If you want to get your data back just use e.g. my_C{1,1} for the first group.
If you have not 3 but n resulting matrices you can use:
Output2 = round(rand(31,15)*10);
idx = uint8(round(1+rand(1,31)*(n-1)));
my_C = cell(1,n);
for k=1:n
my_C(1,k) = {Output2(idx==k,:)};
end
Where n is a positive integer number
I would recommend a slighty different approach. Except for making the rest of the code more maintainable it may also slightly speed up the execution. This due to that matlab uses a JIT compiler and eval must be recompiled every time. Try this:
nMatrices = 3
for k = 1:nMatrices
C{k} = Output2(idx==k,:);
end
As patrik said in the comments, naming variables like this is poor practice. You would be better off using cell arrays M{1}=C1, or if all the Ci are the same size, even just a 3D array M, for example, where M(:,:,1)=C1.
If you really want to use C1, C2, ... as you variable names, I think you will have to use eval, as arielnmz mentioned. One way to do this in matlab is
for i=1:3
eval(['C' num2str(idx(i)) '=[C' num2str(idx(i)) ';Output2(' num2str(i) ',:)];'])
end
Edited to add test code:
idx=[2 1 3 2 2 3];
Output2=rand(6,4);
C1a=[];
C2a=[];
C3a=[];
for i = 1:length(idx)
if idx(i) == 1
C1a = [C1a; Output2(i,:)];
end
if idx(i) == 2
C2a = [C2a; Output2(i,:)];
end
if idx(i) == 3
C3a = [C3a; Output2(i,:)];
end
end
C1=[];
C2=[];
C3=[];
for i=1:length(idx)
eval(['C' num2str(idx(i)) '=[C' num2str(idx(i)) ';Output2(' num2str(i) ',:)];'])
end
all(C1a(:)==C1(:))
all(C2a(:)==C2(:))
all(C3a(:)==C3(:))

MATLAB convert from struct to table and ouput as csv

As part of an image processing pipeline using 'regionprops' in Matlab I generate the struct:
vWFfeatures =
1631x1 struct array with fields:
Area
Centroid
MajorAxisLength
MinorAxisLength
Eccentricity
EquivDiameter
Where 'Centroid' is a Vector containing [x, y] for example [12.4, 26.2]. I would like to convert this struct to a table and save as a CSV file. The objective is to separate the 'Centroid' vector into two columns in the table labelled Centroid_X and Centroid_Y for example. I am not sure how to achieve this.
So far I have investigated using the 'struct2table' function. This ouputs the 'Centroid' as one column. In addition when I try to assign the output to a variable I get an error:
table = struct2table(vWFfeatures)
Error using struct2table
Too many output arguments.
I cannot understand this, any help please?
Since the original struct2table isn't available to you, you might want to implement specifically the behavior you're trying to achieve yourself.
In this case, this means extracting the values you want to save, (split the array,) then save the data:
data_Centroid = vertcat(vWFfeatures.Centroid); %// contains the centroid data
Centroid_X = data_Centroid(:,1); %// The first column is X
Centroid_Y = data_Centroid(:,2); %// the second column is Y
csvwrite('centroid.csv',data_Centroid); %// writes values into csv
If you want column headers in your csv, it gets complicated because csvwrite can only handle numeric arrays:
celldata = num2cell(num2str(data_Centroid)); %// create cell array
celldata(:,3) = celldata(:,4); %// copy col 4 (y data) into col 3 (spaces)
for i=1:length(celldata)
celldata{i,2} = ','; %// col 2 has commas
celldata{i,4} = '\n'; %// col 4 has newlines
end
celldata = celldata'; %'// transpose to make the entries come columnwise
strdata = ['Centroid_X,Centroid_Y\n',celldata{:}]; %// contains all as string
fid = fopen('centroid.csv','w'); % writing the string into the csv
fprintf(fid,strdata);
fclose(fid);
This is how I solved it in the end: extracted each field from struct used horzcat to join into a new array then defined headers and used csvwrite_with_headers, to ouput to csv.
wpbFeatures = regionprops(vWFlabelled, 'Area','Centroid', 'MajorAxisLength', 'MinorAxisLength', 'Eccentricity', 'EquivDiameter');
wpbArea = vertcat(wpbFeatures.Area);
wpbCentroid = vertcat(wpbFeatures.Centroid);
wpbCentroidX = wpbCentroid(:,1);
wpbCentroidY = wpbCentroid(:,2);
wpbFeret = max(imFeretDiameter(vWFlabelled, linspace(0,180,201)), [], 2);
wpbMajorAxisLength = vertcat(wpbFeatures.MajorAxisLength);
wpbMinorAxisLength = vertcat(wpbFeatures.MinorAxisLength);
wpbEccentricity = vertcat(wpbFeatures.Eccentricity);
wpbEquivDiameter = vertcat(wpbFeatures.EquivDiameter);
wpbFeatures = horzcat(wpbArea, wpbCentroidX, wpbCentroidY, wpbFeret, wpbMajorAxisLength, wpbMinorAxisLength, wpbEccentricity, wpbEquivDiameter);
headers = {'Area','CentroidX','CentroidY', 'Feret', 'MajorAxisLength', 'MinorAxisLength', 'Eccentricity', 'EquivDiameter'};
csvwrite_with_headers(strcat(PlateName, '_ResultsFeatures.csv'),wpbFeatures,headers);

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

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.