How do I rename a field in a structure array in MATLAB? - matlab

Given a structure array, how do I rename a field? For example, given the following, how do I change "bar" to "baz".
clear
a(1).foo = 1;
a(1).bar = 'one';
a(2).foo = 2;
a(2).bar = 'two';
a(3).foo = 3;
a(3).bar = 'three';
disp(a)
What is the best method, where "best" is a balance of performance, clarity, and generality?

Expanding on this solution from Matthew, you can also use dynamic field names if the new and old field names are stored as strings:
newName = 'baz';
oldName = 'bar';
[a.(newName)] = a.(oldName);
a = rmfield(a,oldName);

Here's a way to do it with list expansion/rmfield:
[a.baz] = a.bar;
a = rmfield(a,'bar');
disp(a)
The first line was originally written [a(:).baz] = deal(a(:).bar);, but SCFrench pointed out that the deal was unnecessary.

Here's a a way to do it with struct2cell/cell2struct:
f = fieldnames(a);
f{strmatch('bar',f,'exact')} = 'baz';
c = struct2cell(a);
a = cell2struct(c,f);
disp(a)

Related

MATLAB: How to dynamically access variables

I declared some variables comprising of simple row vectors which represents input parameters for another function. Within a loop these variables should be used and the result will be assigned to a structure.
Now, my question is how to best access the content of the predefined variables. I found a solution using eval. However, I often read that the usage of eval should be avoided. Apparently it's not best practice. So, what's best practice for my problem?
varABC = [1,2,3];
varDEF = [4,5,6];
varGHI = [7,8,9];
names = {'ABC','DEF','GHI'};
result = {'result1','result2','result3'};
for i = 1 : 3
varString = strcat('var',names{i});
test.(result{i}) = sum(eval(varString));
end
I would suggest rewriting your code a little bit
names = {'ABC','DEF','GHI'};
result = {'result1','result2','result3'};
option 1
% Use struct instead of a simple variable
var.ABC = [1,2,3];
var.DEF = [4,5,6];
var.GHI = [7,8,9];
for i = 1 : 3
test.(result{i}) = sum(var.(names{i}));
end
option 2
% Use dictionary
c = containers.Map;
c('ABC') = [1,2,3];
c('DEF') = [4,5,6];
c('GHI') = [7,8,9];
for i = 1 : 3
test.(result{i}) = sum(c(names{i}));
end

Convert struct fields from string to number

I have a struct with several fields, some that should be numeric, and some that should be char. However, after my use of regexp I have chars in the fields that I want to use as numbers.
For example:
foo.str = 'one';
foo.data = '1';
foo(2).str = 'two';
foo(2).data = '2';
In my dreams I could do: foo.data = str2double(foo.data), but this does not work.
I could iterate through the struct, but that's only an ok option.
It's a long struct (100,000) with about 20 files.
for i = 1:length(foo)
foo(i).data = str2double(foo(i).data);
end
Any ideas?
Collect all elements from the subfield and call str2double once:
str2double({foo.data})
Here is a fairly compact solution that deals numerical values back into each foo.data:
fdnc = num2cell(str2double({foo.data}));
[foo.data] = deal(fdnc{:});
Remember to clear and redefine foo when testing.
EDIT: Fixed vertcat problem with multiple digits. Thanks, nispio.
A little cumbersome, but this works; no loops:
N = length(foo);
[aux_str{1:N}] = deal(foo.str);
[aux_data{1:N}] = deal(foo.data);
aux_data = mat2cell(str2double(aux_data),1,ones(1,N));
foo = cell2struct([aux_str; aux_data],{'str','data'},1);

How can I unpack a Matlab structure into function arguments?

Using a combination of this question and this Mathworks help thing on comma sep. lists I came up with this ugly way to make my formatting arguments a little prettier:
formatting{1,1} = 'color'; formatting{2,1} = 'black';
formatting{1,2} = 'fontweight'; formatting{2,2} = 'bold';
formatting{1,3} = 'fontsize'; formatting{2,3} = 24;
xlabel('Distance', formatting{:});
But it's still kinda ugly...is there a way to unpack a structure into a bunch of arguments a la a Python dictionary to **kwargs?
For instance, if I had the (IMHO) cleaner structure:
formatting = struct()
formatting.color = 'black';
formatting.fontweight = 'bold';
formatting.fontsize = 24;
Can I just pass that in somehow? If I try directly (xlabel('blah', formatting), or formatting{:}, it craps out saying "Wrong number of arguments".
You are very close. Just switch to a 1-D cell array.
formatting = {'Color', 'Red', 'LineWidth', 10};
figure
plot(rand(1,10), formatting{:})
If you really want to use a struct for formatting arguments, you can unpack it to a cell array and use it like above.
formattingStruct = struct();
formattingStruct.color = 'black';
formattingStruct.fontweight = 'bold';
formattingStruct.fontsize = 24;
fn = fieldnames(formattingStruct);
formattingCell = {};
for i = 1:length(fn)
formattingCell = {formattingCell{:}, fn{i}, formattingStruct.(fn{i})};
end
plot(rand(1,10), formatting{:})
It's probably a good idea to do the struct unpacking a separate little function so you can reuse it easily.
You can convert your structure to cell array with this function:
function c = struct2opt(s)
fname = fieldnames(s);
fval = struct2cell(s);
c = [fname, fval]';
c = c(:);
Then
formatting = struct2opt(formattingStructure);
xlabel('Distance', formatting{:});

Removing items from a structure array in matlab

I have a very large structure array in matlab. Suppose, for argument's sake, to simplify the situation, I have something like:
structure(1).name = 'a';
structure(2).name = 'b';
structure(3).name = 'c';
structure(1).returns = 1;
structure(2).returns = 2;
structure(3).returns = 3;
Now suppose I have some condition that comes along and makes me want to delete everything from structure(2) (any and all entries in my structure array). What is a good way to do that?
My solution has been to just set the corresponding fields to [] (e.g. structure(1).name = [];), but that doesn't remove them, that only makes them empty. How do I actually remove them completely from the structure array? Is there a way?
simple if you want to delete element at index i do the following:
i = 3
structure(i) = [];
And that will remove element at index 3.
Example:
st.name = 'text';
st.id = 1524;
arrayOfSt = [st st st st st];
Now:
arrayOfSt =
1x5 struct array with fields:
name
id
If we execute:
arrayOfSt(2) = [];
then the new value of the array of structers will be:
arrayOfSt =
1x4 struct array with fields:
name
id
Try it !

Iterate through a MATLAB structure numerically

Is it possible to iterate through a MATLAB structure numerically like a vector instead of using the field names?
Simply, I am trying to do the following inside an EML block for Simulink:
S.a.type = 1;
S.a.val = 100;
S.a.somevar = 123;
S.b.type = 2;
S.b.val = 200;
S.b.somevar2 = 234;
S.c.type = 3;
S.c.val = 300;
S.c.somevar3 = 345;
for i = 1:length(s)
itemType = S(i).type;
switch itemType
case 1
val = S(i).val * S(i).somevar1;
case 2
val = S(i).val * S(i).somevar2;
case 3
val = S(i).val * S(i).somevar3;
otherwise
val = 0
end
end
disp(var);
You should be able to generate the fieldnames dynamically using sprintf using something like the following:
for i = 1:length(s)
theFieldName = sprintf('somevar%d', S(i).type);
val = S(i).val * getfield(S(i), theFieldName);
end
You need to use the field names, but you can do so dynamically. If you have a structure defined as:
s.field1 = 'foo';
s.field2 = 'bar';
Then you can access the field field1 with either
s.field1
s.('field1')
The only thing you need is the function fieldnames to dynamically get the field names such that your code example will look somewhat like
elements = fieldnames(S);
for iElement = 1:numel(elements)
element = S.(elements{iElement});
itemType = element.type;
switch itemType
case 1
val = element.val * element.somevar1;
case 2
val = element.val * element.somevar2;
case 3
val = element.val * element.somevar3;
end
end
If those are the exact field names, you should do some other things. First of all you would need to rethink your names and secondly you could use part of Matt's solution to simplify your code.