Iterating over a cell array: do for loops work?

118 views (last 30 days)
Ken
Ken on 28 Mar 2024
Commented: Voss on 4 Apr 2024
In the process of analyzing experimental data, I produce a series of arrays of object that are not all the same length. I thought it would be a reasonable strategy to make them each a member of a cell array. Then, thinking as I would think in Python, I can process them by iterating through the cell array, and sub-iterating through each of those arrays to process each object in turn. It isn't working. Here's what I have:
classdef Peak
properties
Amplitude
Time
ActualAmplitude
ActualTime
EventInterval
HWInterval
Start
End
HWStart
HWEnd
Pairing
TOF
StartIndex
NSamples
Partner % index of the second peak in a pair
Exclude % user chooses to exclude this peak from processing
end
Here's what the top level array looks like:
And here's my code for iterating, to produce input for the hist3 graphing operator.
function b3d(sequence, allPeaks)
stage = 1;
j = 1;
x(100000) = 0;
y(100000) = 0;
for group = allPeaks
for pcell = group
x(j) = sequence(stage);
p = pcell{1}
y(j)= p(1).ActualAmplitude;
end
end
graphable = [x', y'];
save("gr.mat", "graphable");
end
But it only iterates once! Producing this output. What to do differently?
  1 Comment
Stephen23
Stephen23 on 29 Mar 2024
Edited: Stephen23 on 29 Mar 2024
"Iterating over a cell array: do for loops work?"
Of course they do. It would be odd if they did not. Here are some ways to index into a cell array:
Note that MATLAB is not Python. Rather than splitting the data up into lots of separate (nested) arrays, in MATLAB it is usually better to keep data together as much as possible: one table with some meta-data in a few columns is generally better than lots of separate (nested) arrays. Then you can leverage the efficient inbuilt approaches to data processing:
Having lots of vectors TIME, AMPLITUDE, etc hints that you should be using matrices and arrays more.
MATLAB is based around contiguous arrays of numeric data. Python is not (unless you use some third-party module, e.g. numpy). This fundamentally changes how data should be designed to process it efficiently:

Sign in to comment.

Answers (1)

Voss
Voss on 28 Mar 2024
Edited: Voss on 28 Mar 2024
A few things:
  1. A for loop iterates over the columns of what you give it, so if you give it a column vector (cell array or otherwise) like allPeaks, it iterates once, because the thing has one column. To iterate over each element of a column vector, you can make it a row vector in the for loop statement by transposing it or reshaping it.
  2. Once that is changed, group will be a scalar cell array, so for pcell = group just makes pcell the same as group (and makes that for loop unnecessary). To iterate over the contents of the scalar cell array group, use for pcell = group{1}, in which case pcell takes as values each element of the Peak array group{1}. Then use pcell inside the loop instead of pcell{1}. See below.
  3. In your code, j never changes. I don't know if this is just example code, but as it is only the first row of graphable will ever be non-zero because j never increases beyond 1.
Here's a running example, using struct arrays instead of Peak arrays:
% construct a cell array of struct arrays with an ActualAmplitude field:
siz = [2,9,21,33,47,66];
N = numel(siz);
allPeaks = cell(N,1);
for ii = 1:N
allPeaks{ii} = struct('ActualAmplitude',num2cell(rand(1,siz(ii))));
end
allPeaks
allPeaks = 6x1 cell array
{1x2 struct} {1x9 struct} {1x21 struct} {1x33 struct} {1x47 struct} {1x66 struct}
% check the ActualAmplitude values:
temp = [allPeaks{:}];
[temp.ActualAmplitude]
ans = 1x178
0.5917 0.5443 0.3727 0.4115 0.4991 0.2764 0.0753 0.2299 0.6473 0.0032 0.2679 0.0090 0.3725 0.0210 0.5198 0.4835 0.2812 0.0487 0.5884 0.3015 0.7774 0.1971 0.1024 0.2095 0.5331 0.6826 0.0091 0.2153 0.1524 0.0446
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% modified looping code:
sequence = 1;
stage = 1;
j = 1;
x(100000) = 0;
y(100000) = 0;
for group = allPeaks(:).' % making row vector to iterate over
for pcell = group{1} % group is a scalar cell array, take group{1} to iterate over its contents
x(j) = sequence(stage);
y(j) = pcell.ActualAmplitude;
j = j+1; % increment j
end
end
graphable = [x', y']
graphable = 100000x2
1.0000 0.5917 1.0000 0.5443 1.0000 0.3727 1.0000 0.4115 1.0000 0.4991 1.0000 0.2764 1.0000 0.0753 1.0000 0.2299 1.0000 0.6473 1.0000 0.0032
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
You can maybe avoid at least one of your loops by using the same syntax I used to check the ActualAmplitude values
temp = [allPeaks{:}];
which concatentates the contents of each cell of allPeaks together into a single Peak array, then iterate over that if necessary.
  5 Comments
Voss
Voss on 29 Mar 2024
Any other questions, let me know. Otherwise, please Accept this Answer. Thanks!
Voss
Voss on 4 Apr 2024
Hey @Ken, did this answer answer your questions? If so, Accept it.

Sign in to comment.

Categories

Find more on Data Type Conversion in Help Center and File Exchange

Products


Release

R2023b

Community Treasure Hunt

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

Start Hunting!