Generate new variables based on expressions in structure array using loops -- example provided need help to fix
조회 수: 2 (최근 30일)
이전 댓글 표시
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
댓글 수: 0
채택된 답변
Guillaume
2014년 8월 26일
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
Guillaume
2014년 8월 27일
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
추가 답변 (1개)
Geoff Hayes
2014년 8월 25일
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
Geoff Hayes
2014년 8월 26일
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?
참고 항목
카테고리
Help Center 및 File Exchange에서 Tables에 대해 자세히 알아보기
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!