Finding smallest value in nested structure

7 views (last 30 days)
B
B on 30 Aug 2012
Answered: Jos (10584) on 17 Mar 2015
Dear all,
I have a structure as shown here:
subject(i).cineLoop.frame(j).data(k).area
Where 'area' is an amount (e.g. 2328).
How can I find the smallest area in the entire structure? Do I have to resort to for loops? Or am I better off using a different kind of container?
I found another thread concerning this problem: http://www.mathworks.nl/matlabcentral/answers/40479-multi-level-indexing , however I didn't manage to get the solution working for structures with more than 2 levels.
Any help is much appreciated!

Answers (3)

Robert Cumming
Robert Cumming on 30 Aug 2012
One way is to use a self calling function (this will find "area" at any level):
Here is the bones of one - you would call it by:
( yourStruct, 'area' );
function SelfCallingFunction ( str, var )
fnames = fieldnames ( str );
for i=1:length(fnames)
if strcmp ( fnames{i}, var )
disp ( str.(fnames{i} ) );
elseif isstruct ( str.(fnames{i}) )
SelfCallingFunction ( str.(fnames{i}), var )
end
end
end
Note: This will only display the variable in question - but you can expand on this to make it store the "area" and returned it.
There is a bit more work to do - and you really need to do it yourself to learn how it works but also to be able to maintain the code in the future.
  4 Comments
B
B on 30 Aug 2012
Thanks for your reply. I'm glad to hear that for loops are the way to go. I've been using MATLAB for a while now, making the transitition from C++. Since a lot of containers from STL have their own syntax to handle data, I was wondering whether I was overlooking some basic functionality of MATLAB.
Jeremy S
Jeremy S on 17 Mar 2015
Looping through the fieldnames() output is unfortunately the way to do it. Its a little easier if you put a number in the fieldname, i.e. area1, area2, etc... and then use a strcat(['area',str2num(i)]) in a for loop instead of using fieldnames().

Sign in to comment.


Image Analyst
Image Analyst on 30 Aug 2012
Edited: Image Analyst on 30 Aug 2012
Just a guess. Try this (untested):
allAreas = [subject.cineLoop.frame.data.area];
[minArea, indexOfMin] = min(allAreas);
I know it works for cell arrays, such as you get from regionprops(). Add indexes at places if you want to narrow it down. However the index is the index into allAreas, not the i, j, and k separately. You might have to keep track of the min as you traverse your triple for loop if you want to know the i, j, and k individually.
  3 Comments
Darik
Darik on 30 Aug 2012
I think you might have to concatenate one level at a time
allCineLoops = [subject.cineLoop];
allFrames = [allCineLoops.frame];
allData = [allFrames.data];
allArea = [allData.area];
minArea = min(Area);
Image Analyst
Image Analyst on 30 Aug 2012
Try this:
clc;
% Generate some sample data
for i = 1 : 3
for j = 1 : 4
for k = 1 : 5
subject(i).cineLoop.frame(j).data(k).area = rand(1);
end
end
end
tic; % Start timer.
% Now find the smallest area.
% First initialize the min values we want to keep track of.
iAtMinArea = 1;
jAtMinArea = 1;
kAtMinArea = 1;
minArea = inf;
% Now scan the structure looking for the global min.
for i = 1 : 3
for j = 1 : 4
for k = 1 : 5
if subject(i).cineLoop.frame(j).data(k).area < minArea
iAtMinArea = i;
jAtMinArea = j;
kAtMinArea = k;
minArea = subject(i).cineLoop.frame(j).data(k).area;
end
end
end
end
% Found it. Now print them to the command window
toc; % Stop timer and print out elasped time.
fprintf('The min area = %f and occurs at i = %d, j = %d, k = %d.\n',...
minArea, iAtMinArea, jAtMinArea, kAtMinArea)
% Typical printout:
% Elapsed time is 0.001091 seconds.
% The min area = 0.010271 and occurs at i = 3, j = 3, k = 5.

Sign in to comment.


Jos (10584)
Jos (10584) on 17 Mar 2015
I think the for-loop approach is the best option. You can use that to store each value in a matrix first:
Ni = numel(subject)
Nj = numel(subject(1).cineLoop.frame)
Nk = numel(subject(1).cineLoop.frame(1).data)
Area = zeros(Nk,Nj,Nk) ;
for i=1:Ni
for j=1:Nj
for k=1:Nk
Area(i,j,k) = subject(i).cineLoop.frame(j).data(k).area ;
end
end
end
[MinArea, idx) = min(Area(:))
[mi,mj,mk] = ind2sub([Ni,Nj,Nk],idx)

Products

Community Treasure Hunt

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

Start Hunting!