Trasform an array of structs with string in an array of structs with numbers

Hi, I have a array of struct: for every struct I want to trasform sting into number with the function datevec and at the end I want to obtain an array of structs with numbers. My code run but at the end I obtain only the value of the last struct and not of all structs. The code is
% Pre-allocated structures
date=repmat(struct('x',0), 1, size(s,2));
dateStart=repmat(struct('Start',0), 1, size(s,2));
dateEnd=repmat(struct('End',0), 1, size(s,2));
%
for i=1:size(s,2)
% gestisce la presenza di struct vuote
if(isempty(s(1,i).locs))
continue
%gestisce l'assenza dei valori di inizio/fine rilevazione
elseif(isempty(s(1,i).places))
continue
else
date=datevec(s(1,i).locs(:,1))
% Data di inizio rilevazione
dateStart=datevec(s(1,i).places.startdate(:,1));
% Data fine rilevazione
dateEnd=datevec(s(1,i).places.endate(:,1));
end
end
Can you help me to find the error?

Answers (1)

That code is a bit buggy, and it is not doing what you think it is:
  1. Some structures are "preallocated" using repmat(struct(...)), but when you read the documentation for the function datevec you will learn that it does not output a structure but in fact a numeric array. So this preallocation is useless because it creates an array of the wrong type.
  2. On every iteration you completely reassign the variables date, dateStart and dateEnd, so on every loop iteration they get completely redefined. This happens because you do not use any indexing to allocate the output into a new element on each iteration. This is also why the incorrect "preallocation" does not cause any error.
  3. Using the variable name date is a bad idea, as this shadows the inbuilt date function. You can check variable names using which.
  4. the continue operations are not required, they do absolutely nothing useful in this code.
A simpler alternative is to use MATLAB more efficiently:
>> S(3).locs = '2015-03-31';
>> S(2).locs = '2015-02-28';
>> S(1).locs = '2015-01-01';
>> datevec(vertcat({S.locs}))
ans =
2015 1 1 0 0 0
2015 2 28 0 0 0
2015 3 31 0 0 0
OR if the date strings have different lengths or might be missing:
>> X = cellfun(@datevec,{S.locs}','UniformOutput',false);
>> cell2mat(X)
ans =
2015 1 1 0 0 0
2015 2 28 0 0 0
2015 3 31 0 0 0

6 Comments

EDIT: The OP deleted their comment, but I will leave my reply.
You do not tell us how you preallocate those numeric matrices, but possibly they have to wrong number of columns. Try this instead (untested):
nCols = size(s,2);
dateAll = zeros(nCols,6);
dateBeg = zeros(nCols,6);
dateEnd = zeros(nCols,6);
for k = 1:nCols
if ~isempty(s(1,k).locs)
dateAll(k,:) = datevec(s(1,k).locs(:,1))
end
if ~isempty(s(1,k).places)
dateBeg(k,:) = datevec(s(1,k).places.startdate(:,1));
dateEnd(k,:) = datevec(s(1,k).places.enddate(:,1));
end
end
Thanks to your suggest, the code run very good for dateBeg e dateEnd but I have problems for dateAll
Subscripted assignment dimension mismatch.
Error in ProvaS (line 7) dateAll(k,:) = datevec(s(1,k).locs(:,1))
Perhaps there is a string in s(1,k).locs(:,1), but that string is not being converted to a datevector correctly. In this case the isempty test will be passed, but if the string is not a valid date (or is not identified automatically), then the output will not be a 1x6 vector, and this will cause the error.
You should check the data in the location that causes the error: check what is contained in datevec(s(1,k).locs: is it a valid date string? One way to check is to use replace the first if statement with this:
if ~isempty(s(1,k).locs)
str = s(1,k).locs(:,1))
tmp = datevec(str)
dateAll(k,:) = tmp;
end
What are the values of str and tmp that cause the error?
You might need to use the optional second argument to tell datevec the date format used in the string. Read the documentation to know how this works.
The string in s(1,k).locs(:,1) is [] but this don't create problems in DataBeg e DataEnd... the strings are correctly converted in date format. I replace the first if with your last code but it generate an error
Subscripted assignment dimension mismatch.
Error in ProvaStruct (line 10) dateAll(k,:) = tmp;
I use this code
nCols = size(s,2);
%dateAll = zeros(nCols,6);
dateBeg = zeros(nCols,6);
dateEnd = zeros(nCols,6);
for k = 1:nCols
if ~isempty(s(1,k).locs)
str = s(1,k).locs(:,1);
tmp = datevec(str);
dateAll(k,:) = tmp;
end
if ~isempty(s(1,k).places)
dateBeg(k,:) = datevec(s(1,k).places.startdate(:,1));
dateEnd(k,:) = datevec(s(1,k).places.endate(:,1));
end
end
I debug the code and there is an error when the value of tmp is assigned to dateAll: dateAll continue to stay to 0. I have read documentation about datevec but the error is not in the format of date. I think the error is in dimention of dateAll: maybe is necessary to create a dateAll struct. I'm not able to solve this: i try different solutions but nothing
Can you please show the exact date strings that cause this error.
I have solved the problem
% nCols: dimensione dell'array di struct colonne 106
nCols = size(s,2);
% Pre-allocazione delle matrici dateBeg e dateEnd che conterranno
% rispettivamente le date di inizio e di termine della rilevazione
dateBeg = zeros(nCols,6);
dateEnd = zeros(nCols,6);
dateAll(nCols)=struct('date',[]);
% Per k che va da 1 a 106, se i campi s.locs dell'array di struct sono non
% nulli, metto i dati in dateAll
for k = 1:nCols
if ~isempty(s(1,k).locs)
str = s(1,k).locs(:,1);
tmp = datevec(str);
dateAll(k).date = tmp;
end
% if ~isempty(s(1,k).locs)
% dateAll(k,:) = datevec(s(1,k).locs(:,1))
% end
% se i campi s.places non sono vuoti per le struct dell'array, metto i
% valori di startdate e endate rispettivamente in dateBeg e dateEnd
if ~isempty(s(1,k).places)
dateBeg(k,:) = datevec(s(1,k).places.startdate(:,1));
dateEnd(k,:) = datevec(s(1,k).places.endate(:,1));
end
end

This question is closed.

Asked:

on 28 Oct 2015

Closed:

on 20 Aug 2021

Community Treasure Hunt

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

Start Hunting!