Automatically create a several layer structure from a cell array
Afficher commentaires plus anciens
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 commentaires
Dyuman Joshi
le 8 Mar 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
le 8 Mar 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
le 8 Mar 2023
Modifié(e) : Matteo Bonhomme
le 8 Mar 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
le 8 Mar 2023
Stephen23
le 8 Mar 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
le 8 Mar 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.
Réponses (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")
Catégories
En savoir plus sur Matrix Indexing dans Centre d'aide et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!