Applying whos to each field of a struct

11 ビュー (過去 30 日間)
Michael Van de Graaff
Michael Van de Graaff 2022 年 3 月 22 日
編集済み: Stephen23 2022 年 5 月 2 日
I wrote a function to apply the whos function to a struct and all of its fields recurvsively, and I have a strong but inarticulable feeling that either I've rewritten an existing Matlab function, or that i'm commiting bad code practice somehow (it is recursive, which always puts me a bit on guard), so while I don't have a specific question or problem, my general question is "Is this function bad in some way I don't see"
load("teststruct.mat")
[sinfo,sinfotable] = whosstruct(teststruct);
sinfotable
sinfotable = 44×9 table
name size bytes class global sparse complex nesting persistent ________________________________________ ______ _____ ___________ ______ ______ _______ __________ __________ {'teststruct' } 1 1 7057 {'struct' } false false false 1×1 struct false {'teststruct.delete_old_results_flag' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.iteration_num' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.asm1_called' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.asm9_called' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_state' } 1 1 1 {'logical'} false false false 1×1 struct false {'teststruct.roi_x_center' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_y_center' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_x_halfwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_y_halfwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.isclosing' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.saveImageSpecificSettings'} 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.leftedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgheight' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgbottomedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.tableheight' } 1 1 8 {'double' } false false false 1×1 struct false
function [sinfo,sinfotable] = whosstruct(s,varargin)
if ~isstruct(s)
error('You must pass a struct')
end
if isempty(varargin)
upperlayername =inputname(1);
else
upperlayername = varargin{1};
end
sinfo = whos('s');
sinfo.name = upperlayername;
snames = fieldnames(s);
snames = cellfun(@string,snames);
for ii = 1:length(snames)
fldname = snames(ii);
sfield = s.(fldname);
sinfo(end+1) = whos('sfield');
sinfo(end).name = [upperlayername,'.',char(fldname)];
if isstruct(sfield)
subsinfo = whosstruct(sfield,sinfo(end).name);
sinfo = [sinfo,subsinfo];
end
end
sinfotable = struct2table(sinfo);
end
I intend to use this function to idenity the bottom levels of a struct which are large in memory compared to some threshold, like the image data of an image vs fields containing the pixel size of the camera and stuff like that. Then I can remove the fields that take up a bunch of space in memory and save the remaining fields which don't take as much space.
(By the way, is there standard language for refering to the parts a nested struct?)
Also, I think this is the first time i've taken advantage of Matlab Answers ability to add files and executable code, so any comments on how i've written this question are appreciated. I've attached a sample struct in teststruct.mat.
  1 件のコメント
Stephen23
Stephen23 2022 年 5 月 1 日
Note that STRING will operate on a cell array of character vectors, so you can replace:
snames = cellfun(@string,snames);
with one STRING() call. But conversion to STRING type is superfluous anyway: you can simply use snames{ii} in the rest of the code and then get rid of CHAR too.

サインインしてコメントする。

採用された回答

Stephen23
Stephen23 2022 年 5 月 1 日
編集済み: Stephen23 2022 年 5 月 1 日
Using a nested function avoids the need for counting input arguments, simplifies the code somewhat, and might make collating the output easier. You should also consider non-scalar structures, even if only to throw an error for them.
load("teststruct.mat")
S = whosstruct(teststruct);
disp(struct2table(S))
name size bytes class global sparse complex nesting persistent ________________________________________ ______ _____ ___________ ______ ______ _______ __________ __________ {'teststruct' } 1 1 7057 {'struct' } false false false 1×1 struct false {'teststruct.delete_old_results_flag' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.iteration_num' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.asm1_called' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.asm9_called' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_state' } 1 1 1 {'logical'} false false false 1×1 struct false {'teststruct.roi_x_center' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_y_center' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_x_halfwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_y_halfwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.isclosing' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.saveImageSpecificSettings'} 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.leftedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgheight' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgbottomedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.tableheight' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.figure_position_settings2'} 1 4 32 {'double' } false false false 1×1 struct false {'teststruct.figure_position_settings' } 1 4 32 {'double' } false false false 1×1 struct false {'teststruct.summary' } 1 1 704 {'struct' } false false false 1×1 struct false {'teststruct.summary.leftedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.summary.imgheight' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.summary.imgbottomedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.summary.imgwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.draw' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.index' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.exampleind' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.fixangleattempts' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.save_this_iteration' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.stage' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.local_fit_coefficient' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.ftn_tol' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p' } 1 1 1224 {'struct' } false false false 1×1 struct false {'teststruct.p.global' } 1 1 1056 {'struct' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_peak' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_rx' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_ry' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_x0' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_y0' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_ang' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.result_org_flag' } 1 1 8 {'double' } false false false 1×1 struct false
function W = whosstruct(S)
assert(isstruct(S),'Input <S> must be a structure.')
assert(isscalar(S),'Input <S> must be scalar.')
W = whos('S');
W.name = inputname(1);
recfun(S,W.name)
%
function recfun(A,N)
F = fieldnames(A);
for k = 1:numel(F)
T = sprintf('%s.%s',N,F{k});
B = A.(F{k});
D = whos('B');
D.name = T;
W(end+1) = D;
if isstruct(B)
assert(isscalar(B),'Structure <%s> must be scalar.',T)
recfun(B,T)
end
end
end
end

その他の回答 (1 件)

Voss
Voss 2022 年 4 月 30 日
The only problem with this that I see is that sub-structs get repeated in the output. See, e.g., 'teststruct.summary':
load("teststruct.mat")
[sinfo,sinfotable] = whosstruct(teststruct);
disp(sinfotable(strcmp(sinfotable.name,'teststruct.summary'),:))
name size bytes class global sparse complex nesting persistent ______________________ ______ _____ __________ ______ ______ _______ __________ __________ {'teststruct.summary'} 1 1 704 {'struct'} false false false 1×1 struct false {'teststruct.summary'} 1 1 704 {'struct'} false false false 1×1 struct false
One way to fix that is, instead of erroring-out when whosstruct is passed a non-struct, process its whos struct the same as you would a struct passed in. I've made that change and some other changes that don't really affect the behavior, in a new function whosstruct_new.
[sinfo_new,sinfotable_new] = whosstruct_new(teststruct);
disp(sinfotable_new(strcmp(sinfotable_new.name,'teststruct.summary'),:))
name size bytes class global sparse complex nesting persistent ______________________ ______ _____ __________ ______ ______ _______ __________ __________ {'teststruct.summary'} 1 1 704 {'struct'} false false false 1×1 struct false
disp(sinfotable)
name size bytes class global sparse complex nesting persistent ________________________________________ ______ _____ ___________ ______ ______ _______ __________ __________ {'teststruct' } 1 1 7057 {'struct' } false false false 1×1 struct false {'teststruct.delete_old_results_flag' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.iteration_num' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.asm1_called' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.asm9_called' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_state' } 1 1 1 {'logical'} false false false 1×1 struct false {'teststruct.roi_x_center' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_y_center' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_x_halfwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_y_halfwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.isclosing' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.saveImageSpecificSettings'} 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.leftedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgheight' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgbottomedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.tableheight' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.figure_position_settings2'} 1 4 32 {'double' } false false false 1×1 struct false {'teststruct.figure_position_settings' } 1 4 32 {'double' } false false false 1×1 struct false {'teststruct.summary' } 1 1 704 {'struct' } false false false 1×1 struct false {'teststruct.summary' } 1 1 704 {'struct' } false false false 1×1 struct false {'teststruct.summary.leftedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.summary.imgheight' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.summary.imgbottomedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.summary.imgwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.draw' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.index' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.exampleind' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.fixangleattempts' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.save_this_iteration' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.stage' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.local_fit_coefficient' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.ftn_tol' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p' } 1 1 1224 {'struct' } false false false 1×1 struct false {'teststruct.p' } 1 1 1224 {'struct' } false false false 1×1 struct false {'teststruct.p.global' } 1 1 1056 {'struct' } false false false 1×1 struct false {'teststruct.p.global' } 1 1 1056 {'struct' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_peak' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_rx' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_ry' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_x0' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_y0' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_ang' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.result_org_flag' } 1 1 8 {'double' } false false false 1×1 struct false
disp(sinfotable_new)
name size bytes class global sparse complex nesting persistent ________________________________________ ______ _____ ___________ ______ ______ _______ __________ __________ {'teststruct' } 1 1 7057 {'struct' } false false false 1×1 struct false {'teststruct.delete_old_results_flag' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.iteration_num' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.asm1_called' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.asm9_called' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_state' } 1 1 1 {'logical'} false false false 1×1 struct false {'teststruct.roi_x_center' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_y_center' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_x_halfwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.roi_y_halfwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.isclosing' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.saveImageSpecificSettings'} 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.leftedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgheight' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgbottomedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.tableheight' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.imgwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.figure_position_settings2'} 1 4 32 {'double' } false false false 1×1 struct false {'teststruct.figure_position_settings' } 1 4 32 {'double' } false false false 1×1 struct false {'teststruct.summary' } 1 1 704 {'struct' } false false false 1×1 struct false {'teststruct.summary.leftedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.summary.imgheight' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.summary.imgbottomedge' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.summary.imgwidth' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.draw' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.index' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.exampleind' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.fixangleattempts' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.save_this_iteration' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.stage' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.local_fit_coefficient' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.ftn_tol' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p' } 1 1 1224 {'struct' } false false false 1×1 struct false {'teststruct.p.global' } 1 1 1056 {'struct' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_peak' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_rx' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_ry' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_x0' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_y0' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.p.global.bg_gauss_ang' } 1 1 8 {'double' } false false false 1×1 struct false {'teststruct.result_org_flag' } 1 1 8 {'double' } false false false 1×1 struct false
function [sinfo,sinfotable] = whosstruct_new(s,upperlayername)
if nargin < 2
upperlayername = inputname(1);
end
sinfo = setfield(whos('s'),'name',upperlayername);
if strcmp(sinfo.class,'struct')
snames = fieldnames(s);
snames_full = strcat(upperlayername,'.',snames);
for ii = 1:numel(snames)
sinfo = [sinfo,whosstruct_new(s.(snames{ii}),snames_full{ii})];
end
end
if nargout > 1
sinfotable = struct2table(sinfo);
end
end
function [sinfo,sinfotable] = whosstruct(s,varargin)
if ~isstruct(s)
error('You must pass a struct')
end
if isempty(varargin)
upperlayername =inputname(1);
else
upperlayername = varargin{1};
end
sinfo = whos('s');
sinfo.name = upperlayername;
snames = fieldnames(s);
snames = cellfun(@string,snames);
for ii = 1:length(snames)
fldname = snames(ii);
sfield = s.(fldname);
sinfo(end+1) = whos('sfield');
sinfo(end).name = [upperlayername,'.',char(fldname)];
if isstruct(sfield)
subsinfo = whosstruct(sfield,sinfo(end).name);
sinfo = [sinfo,subsinfo];
end
end
sinfotable = struct2table(sinfo);
end
  2 件のコメント
Stephen23
Stephen23 2022 年 5 月 1 日
編集済み: Stephen23 2022 年 5 月 2 日
Good analysis and code modifications.
Note that several type conversions can be avoided (STRING & CHAR).
Voss
Voss 2022 年 5 月 1 日
編集済み: Voss 2022 年 5 月 2 日
Thank you.

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeStructures についてさらに検索

製品


リリース

R2020b

Community Treasure Hunt

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

Start Hunting!

Translated by