Generate new variables based on expressions in structure array using loops -- example provided need help to fix

1 visualizzazione (ultimi 30 giorni)
Can someone help direct me on how to get this to work? For example, I would like to create a new variable in the 'var' structure array that identifies the last year for each cell array and then assigns the last value in the data variable.
var.time = cell(4,1);
var.time{1,1}={'2011';'2012';'2013';'2014'};
var.time{2,1}={'2011';'2012';'2013'};
var.time{3,1}={'2011';'2012'};
var.time{4,1}={'2011';'2012';'2013';'2014';'2015'};
var.data{1,1} = {1;2;3;4};
var.data{2,1} = {1;2;3};
var.data{3,1} = {1;2};
var.data{4,1} = {1;2;3;4;5};
[m,n] = size(var.time);
for j = 1:m;
varName{j,1} = ['var.',var.time{j,1}{end,1},'{',num2str(j),'}'];
var.(varName{j,1}) = var.data{j,1}{end,1};
end

Risposta accettata

Guillaume
Guillaume il 26 Ago 2014
I'm a bit confused by what you're asking as you seem to have the answer in your question. It's just that the name you generate is not a valid field name because of the dot.
To create / use a field whose name you generate from an expression, use dynamic field names which are enclosed in brackets:
for year = [2011 2012 2013]
fname = sprintf('Min%d', year);
s.(fname) = year;
end
If you end up creating field names that are not valid, you can transform them into valid field names with genvarname.
  6 Commenti
Guillaume
Guillaume il 27 Ago 2014
A few things first,
First of all, you should have accepted the answer and started a new question.
Secondly, you're using vectors (not matrices) so most indexing can just be done with varname{index} instead of varname{index, 1}. I find it much clearer. The only difference is when you create varname with _varname{index}, it'll create a row vector instead of a column vector.
Thirdly, it's not clear to me what are temporary variables and what are actual variables you want to store. Is var.year important? What about var.uniqueYears?
Fourth, dates_1 and dates are clearly temporary. Is there any reason to make them a cell array? You can also dispense with dates_1 altogether and calculate dates directly from var.year.
With all that said, I think this is what you want:
var.time = cell(4, 1);
var.data = cell(4, 1);
var.time{1} = (now:-1:(now - ((365*3)+1)))';
var.time{2} = (now:-1:(now - ((365*2)+1)))';
var.time{3} = (now:-1:(now - ((365*5)+1)))';
var.time{4} = (now:-1:(now - ((365*4)+1)))';
var.year = cell(size(var.time));
for j = 1:numel(var.time)
date = datevec(var.time{j}); %no need to go through datestr.
var.year{j} = date(:, 1);
var.data{j} = rand(numel(var.year{j}), 1); %double by default
end
for year = unique(vertcat(var.year{:}))' %vertcat since you're using column vectors.
var.(sprintf('min%d', year)) = cellfun(@(y, d) min(d(y == year)), var.year, var.data, 'UniformOutput', false)';
%note that the line above will put empty matrices for missing years
%if you really do want NaNs uncomment the following line
%var.(sprintf('min%d', year)){cellfun(@isempty, var.(sprintf('min%d', year)))} = NaN;
end
clear dates j year
Jeff
Jeff il 27 Ago 2014
Thanks Guillaume for all your help.
For the question since it's two parts allow me to still create a second question, if you would like (sorry wasn't thinking).
Thank-you for your point about indexing vector arrays, i guess it's a bad habit but still good to know.
Yes to the temporary variables, actually the whole script is a dummy script based on another file I am working with. Knowing the unique years for each cell array would be something needed, probably don't need to actually store it but would need to know what years are there to assign in the fieldname -- but seeing your answer i guess clearly not :)
Thanks for explaining/showing the alternative date method!!
Overall, thank-you for teaching me some more Matlab!! Program works perfectly ... now to transfer and apply what you taught me.
Cheers

Accedi per commentare.

Più risposte (1)

Geoff Hayes
Geoff Hayes il 25 Ago 2014
Jeff - see the generate field names from variables for details on creating new fields for a structure given a string variable.
In your case, you could do something like
for k=1:m
% create the new field name
fieldName = ['y' var.time{k,1}{end}];
% add the field to the structure with the correct value
data.(fieldName) = var.data{k,1}{end};
end
After the code has completed, var looks like
var =
time: {4x1 cell}
data: {4x1 cell}
y2014: 4
y2013: 3
y2012: 2
y2015: 5
Note that the new field names need to be prefixed with a non-numeric (and non-symbolic) character like 'y'.
The above shows that you can do this, but is this something that you really want? What is the intent behind showing the data in this way?
An alternative would be to create a 4x2 cell array where the first column represents the year and the second column the last value (or a 4x2 matrix since the time and data elements are numeric)
var.lastYearData = cell(m,2);
for k=1:m
% assign the time
var.lastYearData{k,1} = var.time{k,1}{end};
% assign the data
var.lastYearData{k,2} = var.data{k,1}{end};
end
Now, after the code has completed, var looks like
var =
time: {4x1 cell}
data: {4x1 cell}
lastYearData: {4x2 cell}
with
var.lastYearData
ans =
'2014' [4]
'2013' [3]
'2012' [2]
'2015' [5]
I think that this alternative is cleaner that the first suggestion.
Try either option and see what happens!
  2 Commenti
Jeff
Jeff il 26 Ago 2014
Modificato: Jeff il 26 Ago 2014
Hi Geoff, thanks for your help although this is not exactly what I am trying to do in my own dataset. I think my example and question might have been a bit unclear.
Basically I have structured array with hundreds of cell arrays of different lengths. I tried to demonstrate that with the test data provided:
var = {4x1} where each cell has different lengths (for example {1x1} of the structure array contains a {4x1} cell array,{2x1}{3x1} etc.)
what I am doing is taking say the minimum value of each cell array within the structure, creating a scalar for each cell array.
the variable (fieldname) containing that scalar i am trying to automate base on an expression. The minimum value is extracted by year so I am trying to automate the fieldname
The way I currently do the same thing is by manually naming the new field name and then assigning my expression for across all cell arrays. For example:
for j=1:m MyDate.Min2013{j} = expression end
the above adds Min2013 to each of my cell arrays containing a scalar value.
What I would like to automate is the fieldname, which I am currently naming manually as say 'Min2013', but where the year in the fieldname is now determined based on an expression.
Is this possible to do?
-- I will try to get a better example if this is not clear
Geoff Hayes
Geoff Hayes il 26 Ago 2014
Yes, a better example is needed especially as you switched from maximum to minimum, and have mentioned an expression.
what I am doing is taking say the minimum value of each cell array within the structure, creating a scalar for each cell array.
Okay, so this would be (from your above example) 2011 repeated four times: [2011 2011 2011 2011]. How do you expect to handle the case, like this one, where you have four identical scalars? Are you assuming that each cell array starts from the same year, so all will have the same minimum year?
minYear = Inf;
for k=1:m
val = min(str2num(char(var.time{m,:})));
if val<minYear
minYear = val;
end
end
the variable (fieldname) containing that scalar i am trying to automate base on an expression. The minimum value is extracted by year so I am trying to automate the fieldname
What is the expression? Or is this the data part of the var?
The way I currently do the same thing is by manually naming the new field name and then assigning my expression for across all cell arrays. For example:
Something like
fieldName = ['min' num2str(minYear)];
var.(fieldName) = cell(m,1);
for k=1:m
var.(fieldName){k,1} = var.data{k}{1};
end
What I would like to automate is the fieldname, which I am currently naming manually as say 'Min2013', but where the year in the fieldname is now determined based on an expression.
So the above code assumes that the expression is minimum, is that correct? Now you want to use some other expression instead?

Accedi per commentare.

Categorie

Scopri di più su Loops and Conditional Statements in Help Center e File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by