Alternative to using structs as reduction variables in parfor loop

조회 수: 5 (최근 30일)
Tejas
Tejas 2021년 1월 27일
댓글: Tejas 2021년 1월 28일
My code initializes a struct (say init_s) with about 9 fields before going into a parfor loop of iterations (as s). Over a single iteration, the empty arrays in s are filled with data. I'd like to add these arrays together, without having to create 9 different variables for each field. How could I go about doing that? Here is a minimum working example:
init_s = struct('f1',ones(10,1),'f2',zeros(10,1),'f3',50*ones(15,1))
parfor iter = 1:10
s = init_s;
s.f1 = s.f1 * 2;
s.f2 = s.f2 + 5;
s.f3 = s.f3 - 1;
end
I'd like to add the generated arrays individually (s.f1 over all iter, s.f2 over all iter, etc.) so that I can average them later. How can I do that without having to create a lot of variables? Or if I have to, how do I access them in a loop using fieldnames?

채택된 답변

Walter Roberson
Walter Roberson 2021년 1월 27일
s(1:2) = struct('f1',ones(10,1),'f2',zeros(10,1),'f3',50*ones(15,1))
s = 1x2 struct array with fields:
f1 f2 f3
sc = struct2cell(s(:))
sc = 3x2 cell array
{10×1 double} {10×1 double} {10×1 double} {10×1 double} {15×1 double} {15×1 double}
totals = arrayfun(@(R) sum(cat(3,sc{R,:}),3), (1:size(sc,1)).', 'uniform', 0)
totals = 3x1 cell array
{10×1 double} {10×1 double} {15×1 double}
struct_total = cell2struct(totals, fieldnames(s), 1)
struct_total = struct with fields:
f1: [10×1 double] f2: [10×1 double] f3: [15×1 double]
  댓글 수: 3
Walter Roberson
Walter Roberson 2021년 1월 28일
If you need to know the value of the total up to this point, then you cannot do that with parfor, as it implies that order is important, but parfor cannot promise any particular order.
If you do not need to know the total until after the parfor, then store the values and do the total afterwards.
init_s = struct('f1',ones(10,1),'f2',zeros(10,1),'f3',50*ones(15,1));
results = struct2cell(structfun(@(x) x*0,init_s,'un',0));
parfor iter = 1:10
s = init_s;
s.f1 = s.f1 * 2;
s.f2 = s.f2 + 5;
s.f3 = s.f3 - 1;
all_s(iter,1) = s;
end
sc = struct2cell(all_s(:));
totals = arrayfun(@(R) sum(cat(3,sc{R,:}),3), (1:size(sc,1)).', 'uniform', 0);
struct_total = cell2struct(totals, fieldnames(all_s), 1);
The code was designed to not care about whether all_s is Nx1 or 1xN or NxM or even higher dimension, as long as the individual arrays in the fields are vectors or 2D. It would, however, need a small change if the fields could be higher dimensional. Though if you care about the shape of all_s then afterwards
struct_total = reshape(struct_total, size(all_s));
Tejas
Tejas 2021년 1월 28일
This works for me. I only care about the total after the iterations, since I want to average it. I think the point I missed was that variables collecting data every iteration are available outside the loop, unlike the temporary variables. I was confused why all_s can be accessed outside the loop. Anyway, thank you!

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

Help CenterFile Exchange에서 Loops and Conditional Statements에 대해 자세히 알아보기

제품


릴리스

R2020b

Community Treasure Hunt

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

Start Hunting!

Translated by