MATLAB: deleting elements from multi-level cell - arrays

I've got a large multi-level cell and I'm trying to delete parts of it within a for loop but can't get past "Error: The expression to the left of the equals sign is not a valid target for an assignment."
Have tried a few versions and keep hitting the same error.
for i=1:length(List{1}{17}{imagenum})
if List{1}{17}{imagenum}(i)>1
List{1}{17}{imagenum}(i)=[];
end
end
Separate question: When I delete parts of a cell/anything within a for loop, is there a standard/smart way of making sure the for loop stays on track? I've been using a variable to keep track of deletions but I'm assuming there's a smarter way of doing this:
deletions=0;
for i=1:length(List{1}{17}{imagenum})
if List{1}{17}{imagenum}(i-deletions)>1
List{1}{17}{imagenum}(i-deletions)=[];
deletions=deletions+1;
end
end

Let's assign List{1}{17}{imagenum} to a:
a = List{1}{17}{imagenum};
Is 'a' cell or array? If it is array:
for i = numel(a):-1:1
if a(i)>1, a(i) = []; end
end
Easier way should be:
a(a>1) = [];
If it is cell:
for i = numel(a):-1:1
if a{i}>1, a(i) = []; end
end
General rule: when you delete items in a loop, you start from the end, not the beginning.

Related

How to remove rows from a struct based on a condition?

I want to delete rows from a struct using a condition which is if hsvmean field = 0 then delete the row. I tried this code:
for j =1:length(selectedIms) % the length of selectedIms is 100
if selectedIms(j).hsvmean == 0
selectedIms(j)=[];
end
end
But I get this error:
Index exceeds the number of array elements (73).
Error in HSVColorSelection (line 57)
if selectedIms(j).hsvmean == 0
How can I delete these items?
Here’s a solution in case someone needs it. Create a new struct in which there would only be the filtered rows
newSelectedlms = meanValues([meanValues.selected_ims]~= 0);
You’re deleting elements, making the array smaller, as you loop over the elements. The end index you loop over is determined at the start of the loop, hence you will index past the end of the array. You are also skipping over elements.
One simple solution is to loop starting at the back:
for j=length(selectedIms):-1:1
...
end
The other solution is to delete all elements at once. You could build a list of indices to delete in the loop, then delete those elements after the loop. Or do it without a loop:
selectedIms([selectedIms.hsvmean] == 0) = [];

Are my arrays incompatible?

I am trying to loop through an array that contains split strings, done via this line:
repHolder() = Split(rep, ",")
That's all fine and good, however, when I try to loop through this repHolder() array via a for loop, I am met each time with a subscript out of range error.
This makes no sense to me. When I step through the array it fails on the first element every time; this line:
If repHolder(j) = counter Then
I tried setting j to 0 and 1, both of which failed on the first sequence of the loop. This suggests to me because the array doesn't have a defined size; that I cannot loop through it this way, but that still makes little sense to me as it is still filled with elements.
Here is the entire code block of what I am trying to do:
Dim repHolder() As String
Dim strHolder() As String
Dim counter As Variant
Dim j As Integer
For Each rep In repNames()
repHolder() = Split(rep, ",")
Next rep
For Each rangeCell In repComboRange
k = 1
Do
If rangeCell.Value = repCombos(k) Then 'At this point, if rangecell = repcombos(k)
Range(rangeCell, rangeCell.End(xlToRight)).Copy
strHolder() = Split(rangeCell.Value, "/")
For Each counter In strHolder()
Stop
For j = 1 To 17
If repHolder(j) = counter Then
You are looping through repNames() and setting this new array via split (over and over again for each repName element...)
For Each rep In repNames()
repHolder() = Split(rep, ",")
Next rep
Every iteration of this loop resets repHolder() to a split of the rep element dropping whatever values were just set in that array in the previous iteration. So once it's done only the last element of RepNames() has been split into the repHolder() array.
For instance, if RepNames() looks like:
Element 0: "james,linda,mahesh,bob"
Element 1: "rajesh,sam,barb,carrie"
Element 2: ""
Then after all this iterating your repHolder array is going to be empty because there is nothing in the final element.
Stick a breakpoint (F9) on you For Each rangeCell In repComboRange line and look at your Locals pane in VBE. Check out the values that are stored in your repHolder() array at that point in time. I suspect there will be nothing in there.
The other oddball here is that you are looping 1 through 17. repHolder() will be a 0-based array so that should be 0 through 16. But... even that is nonsense since this really only makes sense as a For Each loop (or to use the uBound(repHolder) to determine how many times to loop:
For Each counter In strHolder()
Stop
For each repHolderElem in repHolder
If repHolderElem = counter Then
....
Next repHolderElem

Pulling out specific column when sometimes, the array is empty

I am trying to pull out a column from inside a cell. However, sometimes, the cell is empty.
For example, if in this line, I try to pull out the last column inside PM25_win{i}, it sometimes has an array inside of size nx28. However, sometimes, the array is zero.
for i = 1:length(years)-1
PM25 = table2array(PM25_win{i}(:,end));
end
When the array is empty, the code stops and I get the error
Subscript indices must either be real positive integers or logicals.
How can I account for both cases so that the code will simply create the PM25 variable as an empty array if PM25_win{i} is empty?
You could simply add an if-else statement in the for loop.
for i = 1:length(years)-1
if isempty(PM25_win{i}(:,end))
PM25 = [];
else
PM25 = table2array(PM25_win{i}(:,end));
end
end

Is there a more efficient way of choosing an element from 1 array and to every element of the same array

I want to, for every element of an array ZAbs, compare it for equality to every element of the array itself and put them into another distinct array. I want the distinct array's elements to have the same index as the ZAbs array.
I did this by creating 4 nested for loops:
for pAbs2 = 1:400
for qAbs2 = 1:300
zAbsCompare = ZAbs(qAbs2, pAbs2);
for pAbs3 = 1:400
for qAbs3 = 1:300
zAbsCompare2 = ZAbs(qAbs3, pAbs3);
if (zAbsCompare == zAbsCompare2)
InitialZModEqualsImag(pAbs2,qAbs2) = InitialZImag(qAbs2, pAbs2);
InitialZModEqualsReal(pAbs2,qAbs2) = InitialZReal(qAbs2, pAbs2);
end
end
end
end
end
However, this runs really slowly. I can't think of a better way to do this, but as I'm inexperienced with MATLAB there's probably something I'm overlooking here. Any help?
EDIT: Fixed an error and restated the question.
You can do the comparison (not sure that's what you want) efficently with bsxfun:
comp = bsxfun(#eq, X, shiftdim(X,-2));
The result comp(m,n,p,q) is 1 if X(m,n) == X(p,q), and 0 otherwise.

Ignore empty cell array and execute the following cell

I want to make a condition that check if the cell array is empty then move to the next.
I got this index exceed matrix dimensions
Looking forward to hear from you
You can use isempty to check if an element is empty or not:
C = cell(5,1);
C{2} = 2;
for ind = 1:length(C)
if ~isempty(C{ind})
disp(['Processing C{' num2str(ind) '}']);
end
end
and never let index of C exceed length(C).

Resources