Automatically create a several layer structure from a cell array
Mostrar comentarios más antiguos
Hello,
I have a signal that vary along three parameters a,b and c wich can take several values.
a can take n different values a1,a2...an
b can take m different values b1,b2,...,bm
c can take p different values c1,c2...cp.
So far I have all the variations stocked in a cell array C of size n*m*p such that C(x,y,z) correspond to my signal with parameter ax, by and cz.
This works but is not very easy to use. Let's say I want to get the signal corresponding to certain parameter I first need to go find the indexes of the wanted parameters (because I know the value of a that I want but not the index to wich it correspond).
My idea was to create a structure S such that
S.ax.by.cz=C(x,y,z)
that way I wont need a correpondance table
So far the only way to do it that I found is
for i=1:n
for j=1:m
for k=1:p
S.(a_value(i)).(b_value(j)).(c_value(j))=C(i,j,k)
end
end
end
I was wondering if a nicer/more efficient solution exist?
PS: I can't put the value directly in the structure when I generate it because the generation is inside a parfor loop. If you have a solution to that issue that would also solve my problem
thanks in advance
7 comentarios
Dyuman Joshi
el 8 de Mzo. de 2023
" Let's say I want to get the signal corresponding to certain parameter I first need to go find the indexes of the wanted parameters..."
Can you give an example? Say the data is
C{1}=[61 43 50 53 95]; %a
C{2}=[63 96 51 45 57 27]; %b
C{3}=[8 67 76 76 83 50 7]; %c
Now what do you want to access?
Also, it's not clear as to how you are storing the data as C(x,y,z)?
Stephen23
el 8 de Mzo. de 2023
"I was wondering if a nicer/more efficient solution exist?"
ND arrays perhaps.
You indicate that the "signal" varies with some parameters which correspond very neatly to indices 1:m, 1:n, and 1:p. It is unclear why you think the replacing this simple index-correspondence with fieldnames would be an improvement (which most likely would be slower and more complex to access).
Matteo Bonhomme
el 8 de Mzo. de 2023
Editada: Matteo Bonhomme
el 8 de Mzo. de 2023
You can keep the indexing approach, but make a function that does the necessary indexing so as to keep the code more legible. If you make it a nested function then you don't have to pass job_array, country_array, etc., to it.
Example:
main()
function main()
salary=arrayfun(@(x) x,randi(100000,[2,2,2]),'UniformOutput',false);
job_array=["doctor","waiter"];
country_array=["USA","France"];
age_array=["less_than_40","more_than_40"];
salary_doctor_USA_less_40 = get_salary("doctor","USA","less_than_40")
salary_doctor_FRE_less_40 = get_salary("doctor","France","less_than_40")
salary_waiter_USA_less_40 = get_salary("waiter","USA","less_than_40")
salary_waiter_FRE_less_40 = get_salary("waiter","France","less_than_40")
salary_doctor_USA_more_40 = get_salary("doctor","USA","more_than_40")
salary_doctor_FRE_more_40 = get_salary("doctor","France","more_than_40")
salary_waiter_USA_more_40 = get_salary("waiter","USA","more_than_40")
salary_waiter_FRE_more_40 = get_salary("waiter","France","more_than_40")
function s = get_salary(job,country,age_group)
idx_job = find(strcmp(job_array,job));
idx_country = find(strcmp(country_array,country));
idx_age = find(strcmp(age_array,age_group));
s = salary(idx_job,idx_country,idx_age);
end
end
Matteo Bonhomme
el 8 de Mzo. de 2023
Stephen23
el 8 de Mzo. de 2023
Aaaah, so you actually have text data.... in which case, a few dynamic fieldnames as you show is probably reasonably efficient. Dynamic fieldnames in some loops is likely the most efficient approach (you could use SETFIELD, but it is slower).
@Voss: forcing meta-data into variable names should be avoided: https://www.mathworks.com/matlabcentral/answers/225435-save-variable-as-string-from-user-input#answer_184104
The approach you show is not easily generalizable nor easily expandable.
Voss
el 8 de Mzo. de 2023
"forcing meta-data into variable names should be avoided"
Yes, you are right. I was following @Matteo Bonhomme's naming pattern, so that he could easily see how the nested function would work.
"The approach you show is not easily generalizable nor easily expandable."
I disagree.
Respuestas (1)
Another approach is to string this out into a table, converting what were labels along each dimension into grouping variables. Starting with the same salary data example, the trick is to use ndgrid.
salary=arrayfun(@(x) x,randi(100000,[2,2,2]),'UniformOutput',false);
job_array=["doctor","waiter"];
country_array=["USA","France"];
age_array=["less_than_40","more_than_40"];
salary = [salary{:}]'
[Job, Country, Age] = ndgrid(job_array,country_array,age_array)
t = table(Job(:), Country(:), Age(:), salary, VariableNames=["Job", "Country","Age","Salary"])
% Now you can either use logical indexing to select data or grouping to do
% calculations that would be equivalent to slicing in your original array:
t.Salary(t.Job=="waiter" & t.Country == "France" & t.Age == "less_than_40")
groupsummary(t,"Country","mean","Salary")
Categorías
Más información sobre Matrix Indexing en Centro de ayuda y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!