Is there an alternative to eval in a struct?

13 views (last 30 days)
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
Akira Agata
Akira Agata on 22 Oct 2021
Still not working.
As shown below, error occurs in the line "subjects.(subjects{i})~" .
subjects = {'subj_1','subj_2','subj_3'};
tasks = {'rest','task1','task2','task3'};
roigroups = {'a','b','c'};
a = {'dlpfc','amyg'};
b = {'insula','postcg'};
c = {'thalamus','nucl_ruber'};
% The dirty way, assume that other structs defined previously:
for i = 1:length(subjects)
for p = 1:length(tasks)
for x = 1:length(roigroups)
for y = 1:eval(strcat('length(',roigroups{x},')'))
subjects.(subjects{i}).(tasks{p}).(roigroups{x}).(eval(strcat(eval('roigroups{x}'),'{y}'))) = struct();
end
end
end
end
Unable to perform assignment because dot indexing is not supported for variables of this type.
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
Matt J
Matt J on 22 Oct 2021
Edited: Matt J on 22 Oct 2021
Okay, but is there an intuitive way to see which task/roi etc. belong to which subject?
In your post, all subjects share the same tasks and roigroups. That's why I think an array makes more sense.
for example, I need to exclude some subjects, and when I do that, I don't want every subsequent subject to go up one row and mess everything.
You would have to show an example of "mess everything". Why couldn't you extract a subset of Subjects using integer indices? e.g.,
subset=Subjects([1,5,7],:)
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'

Categories

Find more on Structures in Help Center and File Exchange

Products

Community Treasure Hunt

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

Start Hunting!