Clear Filters
Clear Filters

how to find values and following values in a struct

5 views (last 30 days)
Hi! I have a struct Interval (attached), that cointained region's location_id, visited by a user in a different days (31) and in different intervals of time (12 intervals of 2 hours). I want to find in the struct for every day (31) if is present the value 21714; if it's present, I want to find the following values.
E.g. I find value 21714 in first row of Interval, so I want like output 21714 and the following values in the same row
a=[21714 1067829]
I find value 21714 in fourth row, interval_8, so I want like output 21714 and the following values in the same row
a =[21714 18417]
and so on for all the values 21714 in the struct.
I don't know how to do, can you help me? I hope the question is clear
  1 Comment
Tim Wilko
Tim Wilko on 9 Jun 2016
Could you please clarify what you mean by each row? Do you want the next number after 21714 to be in the same interval or the same day?
For example, in the case of interval_8, is it the corresponding value in interval_9, or the next entry of interval_8 that you're after?
Thank you,
Tim

Sign in to comment.

Accepted Answer

Guillaume
Guillaume on 9 Jun 2016
Personally, I think that using dynamic field names is just as bad as using dynamic variable names, and yours is a perfect example why. Numbered field names are just as useless as numbered variables. It's better to put it all in a cell array. So, to start with:
Interval = squeeze(struct2cell(Interval))';
Now to find where your 21714 is, we just wrap a comparison into cellfun. You haven't specified what to do for the entries that are matrices. I assume if 21714 is anywhere in the matrix, it's a find, so I wrap it in any:
found = cellfun(@(m) any(m == 21714), Interval);
Now to find the next non-empty value in the row. Her is one way to do it: first find the non-empty elements:
nonempty = ~cellfun(@isempty, Interval);
Then shift, the found array one element to right and cumsum that by column, so you get 1s only in the columns after 21714:
nextrows = cumsum([zeros(size(found, 1), 1), found(:, 1:end-1)], 2);
nextrows combined with nonempty gives you all the non-empty columns after 21714. You can just iterate over that to get your pairs:
nextnonemptyrows = nextrows & nonempty;
[rows, cols] = find(found);
pairs = cell(numel(rows), 2); %output
for ridx = 1:numel(rows)
row = rows(ridx); col = cols(ridx);
pairs{ridx, 1} = Interval{row, col}; %matrix containing 21714
nextcol = find(nextnonemptyrows(row, :), 1); %column of next non empty matrix in the same row
if ~isempty(nextcol)
pairs{ridx, 2} = Interval{row, nextcol};
end
end
Note that you haven't said what to do if 21714 is in the last column or if there's no non-empty column after it. The above returns empty in that case
  3 Comments
Guillaume
Guillaume on 10 Jun 2016
Essentially, you simply need to remove the , 1 in the find call that limits the number of returned columns to one. Actually, you don't even need the find anymore, you can simple use the row of nextnonemptyrows as is.
In addition, you have to keep all these next values as a cell array, so the assignment to pairs{ridx, 2} needs to be slightly modified. As you're now assigning a cell array, the test for emptiness is not required anymore, so the loop becomes simply:
for ridx = 1:numel(rows)
row = rows(ridx); col = cols(ridx);
pairs{ridx, 1} = Interval{row, col}; %matrix containing 21714
pairs{ridx, 2} = Interval(row, nextnonemptyrows(row, :));
end

Sign in to comment.

More Answers (1)

Sachin Shrestha
Sachin Shrestha on 9 Jun 2016
Hi Elisa,
Perhaps the following code could be another way to deal with the problem: Here, I have assumed, that the value 21714 doesn't exist in the last column. Next, in case of absence of non-empty column following the value, it will add zero instead. Also, for the array following the value, it will save the first element of the array.
load('matlab.mat');
structInterval = Interval;
fields=fieldnames(structInterval); % extract the name of the fields
dataCounter=1;
a=zeros(numel(structInterval),2); % to store the values
val2Check = 21714; % value that is to be checked
for i=1:numel(structInterval) % loop for 31 days to data
for j=1:length(fields) % loop for 12 intervals
valofStruct = structInterval(i).(fields{j}); % get value to be checked
if (valofStruct) % if value is non-empty
if valofStruct == val2Check % if value is the one, here 21714
for k=j+1:length(fields) % check for remaining data in the row, will generate error if the data is in the last row, need to add a condition
valofStruct_2 = structInterval(i).(fields{k});
if(valofStruct_2)
a(dataCounter,:)=[val2Check valofStruct_2(1)]; % keep the value 21714 and following data
dataCounter=dataCounter+1;
% -- do anything else you may want to
break;
elseif k==length(fields) % if empty data in the remaining rows, add zero
a(dataCounter,:)=[val2Check 0];
dataCounter=dataCounter+1;
% -- do anything else, you may want to
end
end
end
end
end
end
a=a(1:dataCounter-1,:); % extract only the non-empty data from 'a'
disp(a);
Hope this will be helpful. Good Luck!

Categories

Find more on Data Type Conversion in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!