Is there an alternative to eval in a struct?

14 views (last 30 days)
Yasir Çatal
Yasir Çatal on 21 Oct 2021
Answered: Steven Lord on 22 Oct 2021
Hi,
I know that eval is evil, but in this particular case, I couldn't find any other way to do it, so I wanted to ask you if anyone comes up with a more efficient way.
The problem is, I need to define a struct, and structs inside that struct, and more structs inside that struct. I think it would be better to describe it (simplified) this way:
subject = {'subj_1','subj_2','subj_3'};
runs = {'rest','task1','task2','task3'};
roigroups = {'a','b','c'};
a = {'dlpfc','amyg'};
b = {'insula','postcg'};
c = {'thalamus','nucl_ruber'};
subjects = struct();
% The dirty way, assume that other structs defined previously:
for i = 1:length(subject)
for p = 1:length(runs)
for x = 1:length(roigroups)
for y = 1:eval(strcat('length(',roigroups{x},')'))
subjects.(subject{i}).(runs{p}).(roigroups{x}).(eval(strcat(eval('roigroups{x}'),'{y}'))) = struct();
end
end
end
end
Unrecognized function or variable 'tasks'.
It works really well, manually checked, but it's a pain to write and read. Is there a workaround for this type of task?
  4 Comments
Yasir Çatal
Yasir Çatal on 22 Oct 2021
Sorry, I edited now so that it works. Should've checked before, sorry about that.

Sign in to comment.

Accepted Answer

Matt J
Matt J on 22 Oct 2021
Edited: Matt J on 22 Oct 2021
Your data organization seems like it should be reconsidered. In a struct, it doesn't make sense if different fields have essentially the same kind of contents. What I think you really want is a 2D or 3D struct array, something like
subject = {'subj_1','subj_2','subj_3'};
tasks = {'rest','task1','task2','task3'};
M=numel(subject);
N=numel(tasks);
a = struct('dlpfc',[],'amyg',[]);
b = struct('insula',[],'postcg',[]);
c = struct('thalamus',[],'nucl_ruber',[]);
[Subjects(1:M,1:N).a]=deal(a);
[Subjects(1:M,1:N).b]=deal(b);
[Subjects(1:M,1:N).c]=deal(c)
Subjects = 3×4 struct array with fields:
a b c
  5 Comments
Yasir Çatal
Yasir Çatal on 22 Oct 2021
Thanks to everyone that involved, I guess I should go with subsets.

Sign in to comment.

More Answers (2)

Akira Agata
Akira Agata on 22 Oct 2021
I believe it's better to arrange the data as a table rather than the deeply nested structure. How about the following?
subject = {'subj_1','subj_2','subj_3'};
runs = {'rest','task1','task2','task3'};
roigroups = {'a','b','c'};
a = {'dlpfc','amyg'};
b = {'insula','postcg'};
c = {'thalamus','nucl_ruber'};
[p,q,r] = ndgrid(subject, runs, [a,b,c]);
T = table(p(:),q(:),r(:),'VariableNames',{'subject','runs','roi'});
T.roigroups = repelem(roigroups',24,1);
T = movevars(T,'roigroups','Before','roi');
disp(T)
subject runs roigroups roi __________ _________ _________ ______________ {'subj_1'} {'rest' } {'a'} {'dlpfc' } {'subj_2'} {'rest' } {'a'} {'dlpfc' } {'subj_3'} {'rest' } {'a'} {'dlpfc' } {'subj_1'} {'task1'} {'a'} {'dlpfc' } {'subj_2'} {'task1'} {'a'} {'dlpfc' } {'subj_3'} {'task1'} {'a'} {'dlpfc' } {'subj_1'} {'task2'} {'a'} {'dlpfc' } {'subj_2'} {'task2'} {'a'} {'dlpfc' } {'subj_3'} {'task2'} {'a'} {'dlpfc' } {'subj_1'} {'task3'} {'a'} {'dlpfc' } {'subj_2'} {'task3'} {'a'} {'dlpfc' } {'subj_3'} {'task3'} {'a'} {'dlpfc' } {'subj_1'} {'rest' } {'a'} {'amyg' } {'subj_2'} {'rest' } {'a'} {'amyg' } {'subj_3'} {'rest' } {'a'} {'amyg' } {'subj_1'} {'task1'} {'a'} {'amyg' } {'subj_2'} {'task1'} {'a'} {'amyg' } {'subj_3'} {'task1'} {'a'} {'amyg' } {'subj_1'} {'task2'} {'a'} {'amyg' } {'subj_2'} {'task2'} {'a'} {'amyg' } {'subj_3'} {'task2'} {'a'} {'amyg' } {'subj_1'} {'task3'} {'a'} {'amyg' } {'subj_2'} {'task3'} {'a'} {'amyg' } {'subj_3'} {'task3'} {'a'} {'amyg' } {'subj_1'} {'rest' } {'b'} {'insula' } {'subj_2'} {'rest' } {'b'} {'insula' } {'subj_3'} {'rest' } {'b'} {'insula' } {'subj_1'} {'task1'} {'b'} {'insula' } {'subj_2'} {'task1'} {'b'} {'insula' } {'subj_3'} {'task1'} {'b'} {'insula' } {'subj_1'} {'task2'} {'b'} {'insula' } {'subj_2'} {'task2'} {'b'} {'insula' } {'subj_3'} {'task2'} {'b'} {'insula' } {'subj_1'} {'task3'} {'b'} {'insula' } {'subj_2'} {'task3'} {'b'} {'insula' } {'subj_3'} {'task3'} {'b'} {'insula' } {'subj_1'} {'rest' } {'b'} {'postcg' } {'subj_2'} {'rest' } {'b'} {'postcg' } {'subj_3'} {'rest' } {'b'} {'postcg' } {'subj_1'} {'task1'} {'b'} {'postcg' } {'subj_2'} {'task1'} {'b'} {'postcg' } {'subj_3'} {'task1'} {'b'} {'postcg' } {'subj_1'} {'task2'} {'b'} {'postcg' } {'subj_2'} {'task2'} {'b'} {'postcg' } {'subj_3'} {'task2'} {'b'} {'postcg' } {'subj_1'} {'task3'} {'b'} {'postcg' } {'subj_2'} {'task3'} {'b'} {'postcg' } {'subj_3'} {'task3'} {'b'} {'postcg' } {'subj_1'} {'rest' } {'c'} {'thalamus' } {'subj_2'} {'rest' } {'c'} {'thalamus' } {'subj_3'} {'rest' } {'c'} {'thalamus' } {'subj_1'} {'task1'} {'c'} {'thalamus' } {'subj_2'} {'task1'} {'c'} {'thalamus' } {'subj_3'} {'task1'} {'c'} {'thalamus' } {'subj_1'} {'task2'} {'c'} {'thalamus' } {'subj_2'} {'task2'} {'c'} {'thalamus' } {'subj_3'} {'task2'} {'c'} {'thalamus' } {'subj_1'} {'task3'} {'c'} {'thalamus' } {'subj_2'} {'task3'} {'c'} {'thalamus' } {'subj_3'} {'task3'} {'c'} {'thalamus' } {'subj_1'} {'rest' } {'c'} {'nucl_ruber'} {'subj_2'} {'rest' } {'c'} {'nucl_ruber'} {'subj_3'} {'rest' } {'c'} {'nucl_ruber'} {'subj_1'} {'task1'} {'c'} {'nucl_ruber'} {'subj_2'} {'task1'} {'c'} {'nucl_ruber'} {'subj_3'} {'task1'} {'c'} {'nucl_ruber'} {'subj_1'} {'task2'} {'c'} {'nucl_ruber'} {'subj_2'} {'task2'} {'c'} {'nucl_ruber'} {'subj_3'} {'task2'} {'c'} {'nucl_ruber'} {'subj_1'} {'task3'} {'c'} {'nucl_ruber'} {'subj_2'} {'task3'} {'c'} {'nucl_ruber'} {'subj_3'} {'task3'} {'c'} {'nucl_ruber'}

Steven Lord
Steven Lord on 22 Oct 2021
For most of what you're trying to do you could use setfield.
subject = {'subj_1','subj_2','subj_3'};
runs = {'rest','task1','task2','task3'};
roigroups = {'a','b','c'};
a = {'dlpfc','amyg'};
b = {'insula','postcg'};
c = {'thalamus','nucl_ruber'};
subjects = struct();
subjects = setfield(subjects, subject{1}, runs{2}, roigroups{3}, c{1})
subjects = struct with fields:
subj_1: [1×1 struct]
% Checking
subjects.subj_1
ans = struct with fields:
task1: [1×1 struct]
subjects.subj_1.task1
ans = struct with fields:
c: 'thalamus'
For that last input probably I'd make a cell array of cell arrays out of a, b, and c.
D = {a, b, c};
subjects = setfield(subjects, subject{2}, runs{1}, roigroups{2}, D{2}{2})
subjects = struct with fields:
subj_1: [1×1 struct] subj_2: [1×1 struct]
subjects.subj_2.rest.b
ans = 'postcg'

Community Treasure Hunt

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

Start Hunting!