This question already has answers here:
What are some efficient ways to combine two structures in MATLAB?
(5 answers)
Closed 8 years ago.
I'm wondering if there is a convenient way to update a struct with the values of another struct in Matlab.
Here is the code, with the use of fieldnames, numel and a for loop,
fn = fieldnames(new_values);
for fi=1:numel(fn)
old_struct.(fn{fi}) = new_values.(fn{fi});
end
Of course, I don't want to loose the fields in old_struct that are not in new_values, so I can't use the simple old_struct=new_values.
Updating a struct is something we may want to do in a single short line in an interpreter.
Since you are convinced that there is no simpler way to achieve what you want, here is the method described in Loren Shure's article (see link posted in Dan's comment), applied to your example:
%// Remove overlapping fields from first struct
s_merged = rmfield(s_old, intersect(fieldnames(s_old), fieldnames(s_new)));
%// Obtain all unique names of remaining fields
names = [fieldnames(s_merged); fieldnames(s_new)];
%// Merge both structs
s_merged = cell2struct([struct2cell(s_merged); struct2cell(s_new)], names, 1);
Note that this slightly improved version can handle arrays of structs, as well as structs with overlapping field names (this is what I believe you call collision).
Related
This question already has answers here:
The difference between a container map and a struct in matlab
(3 answers)
Closed 4 years ago.
Using Maps like in the example on MathWorks (see below) seem useful on first sight. But on second thought, they're a container structure, just as Matlab's struct variable types. I'm new to Maps and missing the advantage of when to use them as opposed to structs - to break the question down into some measurable parameters: In what some use-cases is using Maps vs structs faster and uses less lines of code?
from MathWorks docs, example:
months = {'Jan','Feb','Mar','Apr'};
rainfall = [327.2 368.2 197.6 178.4];
M = containers.Map(months,rainfall)
vs something similar with structs
months = {'Jan','Feb','Mar','Apr'};
rainfall = [327.2 368.2 197.6 178.4];
for ind=1:numel(months)
s.(months{ind})=rainfall(ind);
end
A container map is more or less an struct with a customized indexing. You can use them, when you prefer referring to an entry by a certain char for instance rather than an index. Let's say you want to recall the value of the rainfall for march.
%Declaration map, as you wrote
months = {'Jan','Feb','Mar','Apr'};
rainfall = [327.2 368.2 197.6 178.4];
M = containers.Map(months,rainfall);
M('Mar') % 197.6
As you see, you not just save a variable, but the reference (as a char, not in the typical way...) as well. For large amounts of data you shouldn'd use maps. Hence I'd recommend you to use maps when you specifically need char references and structs for the rest.
the map is (...) a dictionary, a mapping x --> y without any restrictions on x and y. A struct is a data structure, a way to save data in a logical way. - #hbaderts
Just to remind, if you can use a vector instead of a struct, definitely do so!
You will find other valuable informations about maps at this question.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I want to get the content of a variable from its name as a string:
%suppose that I have structures variables in the workspace:
struct_1=struct('field1' ,"str",'field2',0:5)
struct_2=struct('field1' ,"str",'field2',0:10)
struct_3=struct('field1' ,"str",'field2',0:20)
%and I have an other variable like:
a=5
var2='hello'
%and I want to concatenate all these structures in the same structure
%So i wan to get their name.
%I don't know if there is an other way to get just the structure variables
structures=who(str*)
array=[]
for i=1:length(structures)
array=[array; structures(i). field2]; % here I get an error because the content of structures are string representing the variable name
end
%create the new struct
str='newstr_value'
struct_4=struct('field1',str, 'field2',array)
How to fix this error and is there any way to do this better ?
While I would still highly recommend going back to the point of origin of these dynamically named structures (shame 🔔🔔🔔 on the toolbox creator if this is actually the output...) and fixing this problem there, there is an approach that does not require the use of eval.
Similar to my approach for a tangentially related question, you can save the desired structures to a temporary *.mat file and take advantage of load's optional structure output to consolidate the data structures for access in a more robust programmatic matter.
For example:
struct_1=struct('field1' ,"str",'field2',0:5);
struct_2=struct('field1' ,"str",'field2',0:10);
struct_3=struct('field1' ,"str",'field2',0:20);
save('tmp.mat', '-regexp', '^struct_');
clear
oldworkspace = load('tmp.mat');
varnames = fieldnames(oldworkspace);
nvars = numel(varnames);
% Get original structure fields
% The subsequent steps assume that all input structs have the same fields
fields = fieldnames(oldworkspace.(varnames{1}));
nfields = numel(fields);
% Initialize output struct
for ii = 1:nfields
newstruct.(fields{ii}) = [];
end
newstruct(nvars) = newstruct;
for ii = 1:nvars
for jj = 1:nfields
newstruct(ii).(fields{jj}) = oldworkspace.(varnames{ii}).(fields{jj});
end
end
Gives us:
Yay.
Not sure if your situation absolutely requires dynamic calls of variables by their string names. eval can solve your problem. However, eval is slow. At times, it is unreliable. You can easily have conflicting code as you build various components of your project. And in my experience, there have always been alternatives to eval. In your case, Adriaan outlined an example in his comment.
Since you are only trying to interface with a third-party toolbox, if the number of variables you read is reasonable, you can do the followings with eval.
array=struct;
for i=1:length(structures)
eval(['array(',num2str(i),').field2=',structures{i},';'])
end
If you know all the structs are named struct_#, you can also do
array=struct;
num=3; % the number of outputs from your toolbox
for i=1:num
eval(['array(',num2str(i),').field2=struct_',num2str(i),'.field2;'])
end
Note that your field2 values are all arrays. You can't just create an array and expect each "cell" to carry another array value. Arrays, or rather matrices, in Matlab are a special data type. They only take numerical values. (Matrices are highly optimized in Matlab in various ways. That is why we use Matlab.)
Also note that when you set equality of fields of structs, the equality is by reference. There is no deep copy of the data. Modifying one will modify another. (Just beware of this but don't necessarily rely on it. Deciding when to deep copy things is one of the things we let Matlab handle.)
As well, be careful with the result from who. You need to be absolutely clear with what is in the local scope. Above is assuming your result from calling structures=who(str*) is correct for your application.
This question already has answers here:
Dynamic variables matlab
(2 answers)
Closed 8 years ago.
I was wondering how I can use a for loop to create multiple matrix when given a certain number.
Such as If 3 was given I would need three matricies called: C1, C2 and C3.
k = 3
for i = 1:K
C... = [ ]
end
Not sure how to implement this.
The first thing coming in mind is the eval function mentioned by Dennis Jaheruddin, and yes, it is bad practice. So does the documentation say:
Why Avoid the eval Function?
Although the eval function is very powerful and flexible, it not
always the best solution to a programming problem. Code that calls
eval is often less efficient and more difficult to read and debug than
code that uses other functions or language constructs. For example:
MATLAB® compiles code the first time you run it to enhance performance for future runs. However, because code in an eval
statement can change at run time, it is not compiled.
Code within an eval statement can unexpectedly create or assign to a variable already in the current workspace, overwriting existing
data.
Concatenating strings within an eval statement is often difficult to read. Other language constructs can simplify the syntax in your
code.
The "safer" alternative is the function assignin:
The following will do exactly what you want:
letter = 'C';
numbers = 1:3;
arrayfun(#(x) assignin('base',[letter num2str(x)],[]),numbers)
I know cases where you need to create variables likes this, but in most cases it is better and more convenient to use cell arrays or structs.
The trick is to use a cell array:
k=3
C=cell(k,1)
for t=1:k
C{t}= rand(t)
end
If each matrix is of equal size, you would probably just want a three dimensional matrix rather than a cell array.
You now have one cell array,but can access the matrices like this:
C{2} %Access the second matrix.
The use of eval is almost inevitable in this case:
k = 3;
for i = 1:k
eval(sprintf('C%d = [];', i));
end;
Mind you that generating variable names for data storage rather than indexing them (numerically -- see the solution of Dennis Jaheruddin based on cell arrays -- or creating a dynamic struct with named fields that store the data) is almost always a bad idea. Unless you do so to cope up with some weird scripts that you don't want to / cannot modify that need some variables already created in the global workspace.
This question already has answers here:
How can I index a MATLAB array returned by a function without first assigning it to a local variable?
(9 answers)
Closed 8 years ago.
E.g. I would like to do things such as:
A=4:20;
find(A>5)(2) % want to access the 2nd element of the index array returned by find
Yes, this comes up fairly frequently in different contexts, and the one-line answer is subsref. For your case, it is this:
subsref(find(A>5),struct('type','()','subs',{{2}}))
A much cleaner solution uses an undocumented builtin:
builtin('_paren',find(A>5),2)
As an alternative to ugly syntax or undocumented functionality, you could define a small function like the following,
function outarray = nextind(inarray,inds)
outarray = inarray(inds);
Or an inline function:
nextind = #(v,ii) v(ii);
And call it like nextind(find(A>5),2). This is cleaner than subsref and good if you are doing linear indexing (not subscripts).
This question already has answers here:
Array of Matrices in MATLAB
(6 answers)
Closed 9 years ago.
I am new to programming and I was wondering if my question has a simple implementation. I have a bunch of matrices and I want a way to be able to store them, or be able to easily call them and do operations on them. For example, if I have 100 matrices, called, M1,M2,...M100; is there a way I can rename them so that if I want to call the nth matrix, I can just write M(nth)?
EDIT:
For example, if I want to add M1+M1, M1+M2, ...,M1+M100; I want to be able to write a loop something kind of like,
for i=1:100
AM(i)=M(1)+M(i)
end
Is this possible?
Use cell array
AM = cell(1,100);
and set it as
AM{i} = Mi;
then you can access it as
AM{i};
note the use of {} to access each element of the cell array AM, that is in turn a matrix