How do I use indexing (vectorization?) rather than for loops for dynamic field referencing into a cell array?
5 views (last 30 days)
Show older comments
Daniel Bridges
on 10 Jun 2016
Commented: Daniel Bridges
on 20 Nov 2017
I think there's a way to eliminate for loops by indexing, or perhaps it's called vectorizing. How do I do this?
For example, I'm trying to plot several vectors of different lengths in the same 3D scatter plot. This code stores 34 DICOM ROI items' double arrays in a 1x34 cell array:
info = dicominfo('filename.dcm');
numberofarrays = 34;
datacells = cell(1,numberofarrays);
names = fieldnames(info.ROIContourSequence.Item_9.ContourSequence);
for loop = 1:numberofarrays
datacells(loop) = {info.ROIContourSequence.Item_9.ContourSequence.(names{loop}).ContourData(:,1)};
end
but this code results in the following error:
datacellsfaster(1:34) = {info.ROIContourSequence.Item_9.ContourSequence.(names{1:34}).ContourData(:,1)};
Expected one output from a curly brace or dot indexing expression, but there were 34 results.
Why was it expecting only one output? How do I eliminate for loops through indexing?
0 Comments
Accepted Answer
Guillaume
on 10 Jun 2016
I'm suprised you get Expected one output from a curly brace or dot indexing expression as an error and not Argument to dynamic structure reference must evaluate to a valid field name.
Unfortunately, you cannot pass a cell array as dynamic field names, The dynamic name must be a scalar string so,
.ContourSequence.(name{1:34})
is never going to work.
If all the ContourData have the same size you could eliminate the loop with struct2cell and by concatenating all the CountourData into one big matrix. There's no guarantee that it'd be faster, and it certainly would use up a lot more memory.
You're better off with the loop. In any case, with only 34 iterations that loop should execute very quickly.
4 Comments
Guillaume
on 17 Jun 2016
ismember, as a built-in function, is going to be faster than a loop. The bottleneck is going to be the accumarray calls due to the use of a non-standard accumulation function (the @(x) {x} anonymous function).
In my example, accumarray does not sum the resulting values, it extracts the series of coordinates exactly as you want. The accumulation function I've specified simply wrap the accumulated vectors (all the values that match a depth) into a cell array.
find is indeed often unnecessary and using logical indexing directly will speed up your code by a small amount indeed.
By the way, I forgot to say, another way to write your initial loop
for loop = 1:numberofarrays
datacells(loop) = {info.ROIContourSequence.Item_9.ContourSequence.(names{loop}).ContourData(:,1)};
end
would be, assuming that numberofarrays == numel(fieldnames(info.ROIContourSequence.Item_9.ContourSequence)):
datacells = structfun(@(seq) {seq.ContourData(:, 1)}, info.ROIContourSequence.Item_9.ContourSequence);
structfun iterates over all the fields of ContourSequence and, again, the anonymous function simply wrap the ContourData of each field into a cell array. I don't expect any significant gain in speed with that syntax, the looping may be faster but you now have the cost of a function call (to the anonymous function).
More Answers (1)
geotocho
on 28 Oct 2017
Rather than curly brace indexing, the vectorized way of assigning a command to all cells uses parentheses. Much like the traditional array but in this example A and B are cell arrays of the same size. I wish to assign the row of cells in A to B. In this manner dot indexing is allowed.
B(1,:) = A(1,:);
See Also
Categories
Find more on Data Type Conversion in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!